diff --git a/DEPS b/DEPS
index df9b440..5841d2e 100644
--- a/DEPS
+++ b/DEPS
@@ -209,11 +209,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd51fbe1a78b538ca68c56eeb5e12653852407c92',
+  'skia_revision': '72fb3fcdf0a7a7b093271eb8766c7728c17bea1d',
   # 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': '3b4e7d6656a24f035ed323dfbce822e575785ae3',
+  'v8_revision': 'ce8c2c2e4c61e901b5844e5d0f0abbbbbc904ccc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -221,11 +221,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'c12f594a19b18231e5cdc5ccea09a52cdf52500c',
+  'angle_revision': '9459456b09abc2e75c0c9a67e4b653273087e1eb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '90c0551ca547914f96b32d50bba9c2126b45be41',
+  'swiftshader_revision': '0cfdf0c272cd1e1ac40e95d797baf216721b9026',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -268,7 +268,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '1dffb553613d8bcaa5440d27b411ae1ff22bf68b',
+  'harfbuzz_revision': '7ab0f4eda9a8a1d7ccd334fa7f9fef4b038a1c24',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -288,7 +288,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '97351fd7fb7576415b3855ccee106b69d6ebaac4',
+  'devtools_frontend_revision': '8402fc332631f51cddd1c7562a488e900b0fe59d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -328,7 +328,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': '01407851360e649774cf8f6a0774dbbfbcf8bb63',
+  'dawn_revision': '59e16c9b02a0ef2a094bef900b83f2785b3c2a43',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -654,7 +654,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'qgWjqhDC-d3maWRs-3dh4uTjXicdxi88EYI4HoaVGcgC',
+          'version': 'jbwok3INQjzMDqZtOLyPpUvWdMrA2Ik6lJ-pjM8bvosC',
         },
       ],
       'dep_type': 'cipd',
@@ -665,7 +665,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'M668EbK0TLr4XWelPNWUCwz-8fDE1RMeO0xvXR4Y4rsC',
+          'version': 'C7ucDXsn1avmVkd2AmtllTpESb4IeFnsWdx5Ry95sXkC',
         },
       ],
       'dep_type': 'cipd',
@@ -946,7 +946,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ab07c941767bbaf2afc88c7547b085048001fb2e',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b4d5ad4a85af28a8151c427329984cfa29bbca46',
       'condition': 'checkout_chromeos',
   },
 
@@ -1349,7 +1349,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5f30314fb72eb409b51ff9b9fdc31976ec0f103b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '34eb6a14728a870046c2637dbfb909d02936b84c',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1574,7 +1574,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7c0e4f92088f8230bd63a81b9b924fb9dadc5be8',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '62678f5c7b4d555f345c96dad5eef689e1ceda83',
+    Var('webrtc_git') + '/src.git' + '@' + 'fccb052ee38f4f5e7c5bf1666954b0dedef4223e',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1635,7 +1635,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@003d82101fec3d9c46c1baf377166ee137bc1d3a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3051bb1cf2055b65b92a93c9f84cf6f189cc6998',
     'condition': 'checkout_src_internal',
   },
 
@@ -1650,11 +1650,11 @@
     'dep_type': 'cipd',
   },
 
-  'src/ash/content/help_app_ui/resources/prod': {
+  'src/chromeos/components/help_app_ui/resources/prod': {
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'Tpot8NP1IcTof4WQpeO4pIYUqhLauiOPwiyMN-4FRSkC',
+        'version': 'KXn8zZ3-mP6fa0dmjSEmUcmhZ-1rDhqe1djW922_BJQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1665,7 +1665,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'vU4A4sFU1mlyfYrlVQnoZyVzXFycdSz6Sar5TP_ThaoC',
+        'version': 'Y11GYI292bpvaXxkHj9X5tufQUeYgOWKF_Ozds2OB7MC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7f7e9678..da3f602e 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2466,6 +2466,7 @@
     "//ash/public/cpp:unit_tests",
     "//ash/public/cpp/external_arc:test_support",
     "//ash/public/cpp/external_arc:unit_tests",
+    "//ash/public/cpp/holding_space:test_support",
     "//ash/resources/vector_icons",
     "//ash/shortcut_viewer:unit_tests",
     "//ash/strings",
diff --git a/ash/DEPS b/ash/DEPS
index 60859bc1..21fb9e2 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -101,9 +101,6 @@
   "root_window_controller\.*": [
     "+ash/host"
   ],
-  ".*run_all_unittests.cc": [
-    "+mojo/core/embedder",
-  ],
   "shell.cc": [
     "+ash/host/ash_window_tree_host_init_params.h"
   ],
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 3f7b111..766e31a 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -1047,8 +1047,8 @@
   }
 
   const WMEvent event(action == WINDOW_CYCLE_SNAP_LEFT
-                          ? WM_EVENT_CYCLE_SNAP_LEFT
-                          : WM_EVENT_CYCLE_SNAP_RIGHT);
+                          ? WM_EVENT_CYCLE_SNAP_PRIMARY
+                          : WM_EVENT_CYCLE_SNAP_SECONDARY);
   aura::Window* active_window = window_util::GetActiveWindow();
   DCHECK(active_window);
   WindowState::Get(active_window)->OnWMEvent(&event);
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 8068fdfc..e2ec226 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -721,7 +721,7 @@
   wm::ActivateWindow(window1.get());
   left_clamshell_no_overview = 1;
   test("Snap left, clamshell, no overview", WINDOW_CYCLE_SNAP_LEFT,
-       WindowStateType::kLeftSnapped);
+       WindowStateType::kPrimarySnapped);
   left_clamshell_no_overview = 2;
   test("Unsnap left, clamshell, no overview", WINDOW_CYCLE_SNAP_LEFT,
        WindowStateType::kNormal);
@@ -729,14 +729,14 @@
   EnterOverviewAndDragToSnapRight(window1.get());
   left_clamshell_overview = 1;
   test("Snap left, clamshell, overview", WINDOW_CYCLE_SNAP_LEFT,
-       WindowStateType::kLeftSnapped);
+       WindowStateType::kPrimarySnapped);
   left_clamshell_overview = 2;
   test("Unsnap left, clamshell, overview", WINDOW_CYCLE_SNAP_LEFT,
        WindowStateType::kNormal);
   // Alt+], clamshell, no overview
   right_clamshell_no_overview = 1;
   test("Snap right, clamshell, no overview", WINDOW_CYCLE_SNAP_RIGHT,
-       WindowStateType::kRightSnapped);
+       WindowStateType::kSecondarySnapped);
   right_clamshell_no_overview = 2;
   test("Unsnap right, clamshell, no overview", WINDOW_CYCLE_SNAP_RIGHT,
        WindowStateType::kNormal);
@@ -744,7 +744,7 @@
   EnterOverviewAndDragToSnapLeft(window1.get());
   right_clamshell_overview = 1;
   test("Snap right, clamshell, overview", WINDOW_CYCLE_SNAP_RIGHT,
-       WindowStateType::kRightSnapped);
+       WindowStateType::kSecondarySnapped);
   right_clamshell_overview = 2;
   test("Unsnap right, clamshell, overview", WINDOW_CYCLE_SNAP_RIGHT,
        WindowStateType::kNormal);
@@ -752,7 +752,7 @@
   ShellTestApi().SetTabletModeEnabledForTest(true);
   left_tablet = 1;
   test("Snap left, tablet, no overview", WINDOW_CYCLE_SNAP_LEFT,
-       WindowStateType::kLeftSnapped);
+       WindowStateType::kPrimarySnapped);
   ToggleOverview();
   left_tablet = 2;
   test("Unsnap left, tablet, no overview", WINDOW_CYCLE_SNAP_LEFT,
@@ -761,14 +761,14 @@
   EnterOverviewAndDragToSnapRight(window1.get());
   left_tablet = 3;
   test("Snap left, tablet, overview", WINDOW_CYCLE_SNAP_LEFT,
-       WindowStateType::kLeftSnapped);
+       WindowStateType::kPrimarySnapped);
   left_tablet = 4;
   test("Unsnap left, tablet, overview", WINDOW_CYCLE_SNAP_LEFT,
        WindowStateType::kMaximized);
   // Alt+], tablet, no overview
   right_tablet = 1;
   test("Snap right, tablet, no overview", WINDOW_CYCLE_SNAP_RIGHT,
-       WindowStateType::kRightSnapped);
+       WindowStateType::kSecondarySnapped);
   ToggleOverview();
   right_tablet = 2;
   test("Unsnap right, tablet, no overview", WINDOW_CYCLE_SNAP_RIGHT,
@@ -777,7 +777,7 @@
   EnterOverviewAndDragToSnapLeft(window1.get());
   right_tablet = 3;
   test("Snap right, tablet, overview", WINDOW_CYCLE_SNAP_RIGHT,
-       WindowStateType::kRightSnapped);
+       WindowStateType::kSecondarySnapped);
   right_tablet = 4;
   test("Unsnap right, tablet, overview", WINDOW_CYCLE_SNAP_RIGHT,
        WindowStateType::kMaximized);
diff --git a/ash/app_list/app_list_view_delegate.h b/ash/app_list/app_list_view_delegate.h
index 2c9a5f3..a66e600 100644
--- a/ash/app_list/app_list_view_delegate.h
+++ b/ash/app_list/app_list_view_delegate.h
@@ -37,7 +37,8 @@
 
 class ASH_PUBLIC_EXPORT AppListViewDelegate {
  public:
-  virtual ~AppListViewDelegate() {}
+  virtual ~AppListViewDelegate() = default;
+
   // Gets the model associated with the view delegate. The model may be owned
   // by the delegate, or owned elsewhere (e.g. a profile keyed service).
   virtual AppListModel* GetModel() = 0;
diff --git a/ash/app_list/bubble/scrollable_apps_grid_view.cc b/ash/app_list/bubble/scrollable_apps_grid_view.cc
index bbd44608..5358020 100644
--- a/ash/app_list/bubble/scrollable_apps_grid_view.cc
+++ b/ash/app_list/bubble/scrollable_apps_grid_view.cc
@@ -17,10 +17,6 @@
 // TODO(crbug.com/1211608): Add this to AppListConfig.
 const int kVerticalTilePadding = 8;
 
-gfx::Size GetTileViewSize(const AppListConfig& config) {
-  return gfx::Size(config.grid_tile_width(), config.grid_tile_height());
-}
-
 }  // namespace
 
 ScrollableAppsGridView::ScrollableAppsGridView(
@@ -56,13 +52,18 @@
     } else {
       // If the drag view size changes, make sure it has the same center.
       gfx::Rect bounds = view->bounds();
-      bounds.ClampToCenteredSize(GetTileViewSize(GetAppListConfig()));
+      bounds.ClampToCenteredSize(GetTileViewSize());
       view->SetBoundsRect(bounds);
     }
   }
   views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model());
 }
 
+gfx::Size ScrollableAppsGridView::GetTileViewSize() const {
+  const AppListConfig& config = GetAppListConfig();
+  return gfx::Size(config.grid_tile_width(), config.grid_tile_height());
+}
+
 gfx::Insets ScrollableAppsGridView::GetTilePadding() const {
   int content_width = GetContentsBounds().width();
   int tile_width = GetAppListConfig().grid_tile_width();
@@ -81,6 +82,10 @@
   return grid_size;
 }
 
+void ScrollableAppsGridView::MaybeCreateGradientMask() {
+  // Scrollable apps grid does not have a gradient.
+}
+
 void ScrollableAppsGridView::CalculateIdealBounds() {
   DCHECK(!is_in_folder());
 
diff --git a/ash/app_list/bubble/scrollable_apps_grid_view.h b/ash/app_list/bubble/scrollable_apps_grid_view.h
index 5c61e833..9591b3b 100644
--- a/ash/app_list/bubble/scrollable_apps_grid_view.h
+++ b/ash/app_list/bubble/scrollable_apps_grid_view.h
@@ -26,9 +26,11 @@
   void Layout() override;
 
   // AppsGridView:
+  gfx::Size GetTileViewSize() const override;
   gfx::Insets GetTilePadding() const override;
   gfx::Size GetTileGridSize() const override;
   void CalculateIdealBounds() override;
+  void MaybeCreateGradientMask() override;
 };
 
 }  // namespace ash
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 8d1f1ab8..977beed9 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -31,7 +31,6 @@
 #include "ash/public/cpp/app_list/app_list_config_provider.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/metrics_util.h"
 #include "ash/public/cpp/pagination/pagination_controller.h"
 #include "base/barrier_closure.h"
@@ -43,7 +42,6 @@
 #include "base/numerics/ranges.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -51,7 +49,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/animation_throughput_reporter.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/paint_recorder.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -59,15 +56,12 @@
 #include "ui/gfx/animation/animation.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
-#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/transform_util.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/paint_info.h"
-#include "ui/views/view_model_utils.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
@@ -93,9 +87,6 @@
 // The drag and drop proxy should get scaled by this factor.
 constexpr float kDragAndDropProxyScale = 1.2f;
 
-// The apps grid should be scaled down by this factor.
-constexpr float kCardifiedScale = 0.84f;
-
 // Vertical padding between the apps grid pages in cardified state.
 constexpr int kCardifiedPaddingBetweenPages = 12;
 
@@ -133,13 +124,6 @@
 constexpr gfx::Tween::Type kCardifiedStateTweenType =
     gfx::Tween::LINEAR_OUT_SLOW_IN;
 
-// Returns the size of a tile view excluding its padding.
-gfx::Size GetTileViewSize(const AppListConfig& config, bool cardified_state) {
-  return gfx::ScaleToRoundedSize(
-      gfx::Size(config.grid_tile_width(), config.grid_tile_height()),
-      (cardified_state ? kCardifiedScale : 1.0f));
-}
-
 // RowMoveAnimationDelegate is used when moving an item into a different row.
 // Before running the animation, the item's layer is re-created and kept in
 // the original position, then the item is moved to just before its target
@@ -325,66 +309,8 @@
   return ss.str();
 }
 
-// A layer delegate used for AppsGridView's mask layer, with top and bottom
-// gradient fading out zones.
-class AppsGridView::FadeoutLayerDelegate : public ui::LayerDelegate {
- public:
-  explicit FadeoutLayerDelegate(int fadeout_mask_height)
-      : layer_(ui::LAYER_TEXTURED), fadeout_mask_height_(fadeout_mask_height) {
-    layer_.set_delegate(this);
-    layer_.SetFillsBoundsOpaquely(false);
-  }
-
-  ~FadeoutLayerDelegate() override { layer_.set_delegate(nullptr); }
-
-  ui::Layer* layer() { return &layer_; }
-
- private:
-  // ui::LayerDelegate:
-  // TODO(warx): using a mask is expensive. It would be more efficient to avoid
-  // the mask for the central area and only use it for top/bottom areas.
-  void OnPaintLayer(const ui::PaintContext& context) override {
-    const gfx::Size size = layer()->size();
-    gfx::Rect top_rect(0, 0, size.width(), fadeout_mask_height_);
-    gfx::Rect bottom_rect(0, size.height() - fadeout_mask_height_, size.width(),
-                          fadeout_mask_height_);
-
-    views::PaintInfo paint_info =
-        views::PaintInfo::CreateRootPaintInfo(context, size);
-    const auto& prs = paint_info.paint_recording_size();
-
-    //  Pass the scale factor when constructing PaintRecorder so the MaskLayer
-    //  size is not incorrectly rounded (see https://crbug.com/921274).
-    ui::PaintRecorder recorder(context, paint_info.paint_recording_size(),
-                               static_cast<float>(prs.width()) / size.width(),
-                               static_cast<float>(prs.height()) / size.height(),
-                               nullptr);
-
-    gfx::Canvas* canvas = recorder.canvas();
-    // Clear the canvas.
-    canvas->DrawColor(SK_ColorBLACK, SkBlendMode::kSrc);
-    // Draw top gradient zone.
-    cc::PaintFlags flags;
-    flags.setBlendMode(SkBlendMode::kSrc);
-    flags.setAntiAlias(false);
-    flags.setShader(gfx::CreateGradientShader(
-        gfx::Point(), gfx::Point(0, fadeout_mask_height_), SK_ColorTRANSPARENT,
-        SK_ColorBLACK));
-    canvas->DrawRect(top_rect, flags);
-    // Draw bottom gradient zone.
-    flags.setShader(gfx::CreateGradientShader(
-        gfx::Point(0, size.height() - fadeout_mask_height_),
-        gfx::Point(0, size.height()), SK_ColorBLACK, SK_ColorTRANSPARENT));
-    canvas->DrawRect(bottom_rect, flags);
-  }
-  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
-                                  float new_device_scale_factor) override {}
-
-  ui::Layer layer_;
-  const int fadeout_mask_height_;
-
-  DISALLOW_COPY_AND_ASSIGN(FadeoutLayerDelegate);
-};
+// static
+constexpr float AppsGridView::kCardifiedScale;
 
 AppsGridView::AppsGridView(ContentsView* contents_view,
                            AppListViewDelegate* app_list_view_delegate,
@@ -460,13 +386,13 @@
 }
 
 gfx::Size AppsGridView::GetTotalTileSize() const {
-  gfx::Rect rect(GetTileViewSize(GetAppListConfig(), cardified_state_));
+  gfx::Rect rect(GetTileViewSize());
   rect.Inset(GetTilePadding());
   return rect.size();
 }
 
 gfx::Size AppsGridView::GetTileGridSizeWithPadding() const {
-  gfx::Size size(GetTileViewSize(GetAppListConfig(), cardified_state_));
+  gfx::Size size(GetTileViewSize());
   size.SetSize(size.width() * cols_, size.height() * rows_per_page_);
 
   int horizontal_padding = horizontal_tile_padding_ * 2;
@@ -486,16 +412,14 @@
 
 gfx::Size AppsGridView::GetMinimumTileGridSize(int cols,
                                                int rows_per_page) const {
-  const gfx::Size tile_size =
-      GetTileViewSize(GetAppListConfig(), cardified_state_);
+  const gfx::Size tile_size = GetTileViewSize();
   return gfx::Size(tile_size.width() * cols,
                    tile_size.height() * rows_per_page);
 }
 
 gfx::Size AppsGridView::GetMaximumTileGridSize(int cols,
                                                int rows_per_page) const {
-  const gfx::Size tile_size =
-      GetTileViewSize(GetAppListConfig(), cardified_state_);
+  const gfx::Size tile_size = GetTileViewSize();
   return gfx::Size(tile_size.width() * cols + kMaximumTileSpacing * (cols - 1),
                    tile_size.height() * rows_per_page +
                        kMaximumTileSpacing * (rows_per_page - 1));
@@ -1065,67 +989,6 @@
   return "AppsGridView";
 }
 
-// TODO(crbug.com/1211608): Move to PagedAppsGridView when the pagination model
-// and controller are moved.
-void AppsGridView::Layout() {
-  if (ignore_layout_)
-    return;
-
-  if (bounds_animator_->IsAnimating())
-    bounds_animator_->Cancel();
-
-  if (GetContentsBounds().IsEmpty())
-    return;
-
-  // Update cached tile padding first, as grid size calculations depend on the
-  // cached padding value.
-  UpdateTilePadding();
-
-  // Prepare |page_size| * number-of-pages for |items_container_|, and sets the
-  // origin properly to show the correct page.
-  const gfx::Size page_size = GetTileGridSize();
-  const int pages = pagination_model_.total_pages();
-  const int current_page = pagination_model_.selected_page();
-  if (pagination_controller_->scroll_axis() ==
-      PaginationController::SCROLL_AXIS_HORIZONTAL) {
-    const int page_width = page_size.width() + GetPaddingBetweenPages();
-    items_container_->SetBoundsRect(gfx::Rect(-page_width * current_page, 0,
-                                              page_width * pages,
-                                              GetContentsBounds().height()));
-  } else {
-    const int page_height = page_size.height() + GetPaddingBetweenPages();
-    items_container_->SetBoundsRect(gfx::Rect(0, -page_height * current_page,
-                                              GetContentsBounds().width(),
-                                              page_height * pages));
-  }
-
-  if (fadeout_layer_delegate_)
-    fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
-
-  CalculateIdealBoundsForFolder();
-  for (int i = 0; i < view_model_.view_size(); ++i) {
-    AppListItemView* view = GetItemViewAt(i);
-    if (view != drag_view_) {
-      view->SetBoundsRect(view_model_.ideal_bounds(i));
-    } else {
-      // If the drag view size changes, make sure it has the same center.
-      gfx::Rect bounds = view->bounds();
-      bounds.ClampToCenteredSize(
-          GetTileViewSize(GetAppListConfig(), cardified_state_));
-      view->SetBoundsRect(bounds);
-    }
-  }
-  if (cardified_state_) {
-    DCHECK(!background_cards_.empty());
-    MaybeCreateGradientMask();
-    // Make sure that the background cards render behind everything
-    // else in the items container.
-    for (auto& background_card : background_cards_)
-      items_container_->layer()->StackAtBottom(background_card.get());
-  }
-  views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model_);
-}
-
 void AppsGridView::UpdateControlVisibility(AppListViewState app_list_state,
                                            bool is_in_drag) {
   const bool fullscreen_or_in_drag =
@@ -3340,8 +3203,8 @@
   int page_count = 0;
   if (!folder_delegate_) {
     const auto& pages = view_structure_.pages();
-    for (size_t i = 0; i < pages.size(); ++i) {
-      if (static_cast<int>(pages[i].size()) < TilesPerPage())
+    for (const auto& page : pages) {
+      if (static_cast<int>(page.size()) < TilesPerPage())
         ++page_count;
     }
   } else {
@@ -3362,8 +3225,7 @@
 // TODO(crbug.com/1211608): Move to PagedAppsGridView.
 void AppsGridView::UpdateTilePadding() {
   gfx::Size content_size = GetContentsBounds().size();
-  const gfx::Size tile_size =
-      GetTileViewSize(GetAppListConfig(), cardified_state_);
+  const gfx::Size tile_size = GetTileViewSize();
   if (cardified_state_)
     content_size = gfx::ScaleToRoundedSize(content_size, kCardifiedScale);
 
@@ -3594,24 +3456,6 @@
   }
 }
 
-void AppsGridView::MaybeCreateGradientMask() {
-  if (!folder_delegate_ && features::IsBackgroundBlurEnabled()) {
-    // TODO(newcomer): Improve implementation of the mask layer so we can
-    // enable it on all devices https://crbug.com/765292.
-    if (!layer()->layer_mask_layer()) {
-      // Always create a new layer. The layer may be recreated by animation,
-      // and using the mask layer used by the detached layer can lead to
-      // crash. b/118822974.
-      if (!fadeout_layer_delegate_) {
-        fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>(
-            GetAppListConfig().grid_fadeout_mask_height());
-        fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
-      }
-      layer()->SetMaskLayer(fadeout_layer_delegate_->layer());
-    }
-  }
-}
-
 int AppsGridView::GetPageFlipTargetForDrag(const gfx::Point& drag_point) {
   int new_page_flip_target = -1;
 
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h
index 85cf3b7..efe581d 100644
--- a/ash/app_list/views/apps_grid_view.h
+++ b/ash/app_list/views/apps_grid_view.h
@@ -20,12 +20,9 @@
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/ash_export.h"
 #include "ash/public/cpp/pagination/pagination_model.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "build/build_config.h"
 #include "ui/base/models/list_model_observer.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
@@ -94,6 +91,8 @@
   AppsGridView(ContentsView* contents_view,
                AppListViewDelegate* app_list_view_delegate,
                AppsGridViewFolderDelegate* folder_delegate);
+  AppsGridView(const AppsGridView&) = delete;
+  AppsGridView& operator=(const AppsGridView&) = delete;
   ~AppsGridView() override;
 
   // Initializes the class. Calls virtual methods, so its code cannot be in the
@@ -110,9 +109,6 @@
   // Returns the size of a tile view including its padding.
   gfx::Size GetTotalTileSize() const;
 
-  // Returns the padding around a tile view.
-  virtual gfx::Insets GetTilePadding() const = 0;
-
   // Returns the size of the entire tile grid with padding between tiles.
   gfx::Size GetTileGridSizeWithPadding() const;
 
@@ -190,7 +186,6 @@
 
   // Overridden from views::View:
   gfx::Size CalculatePreferredSize() const override;
-  void Layout() override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   bool OnKeyReleased(const ui::KeyEvent& event) override;
   void ViewHierarchyChanged(
@@ -359,17 +354,34 @@
   int BackgroundCardCountForTesting() const { return background_cards_.size(); }
 
  protected:
-  class FadeoutLayerDelegate;
+  // The cardified apps grid should be scaled down by this factor.
+  static constexpr float kCardifiedScale = 0.84f;
+
+  // Returns the size of a tile view excluding its padding.
+  virtual gfx::Size GetTileViewSize() const = 0;
+
+  // Returns the padding around a tile view.
+  virtual gfx::Insets GetTilePadding() const = 0;
 
   // Returns the size of the entire tile grid.
   virtual gfx::Size GetTileGridSize() const = 0;
 
+  // Creates a layer mask for gradient alpha when the feature is enabled. The
+  // gradient appears at the top and bottom of the apps grid to create a
+  // "fade out" effect when
+  // TODO(crbug.com/1211608): Move to PagedAppsGridView when cardified view
+  // methods move.
+  virtual void MaybeCreateGradientMask() = 0;
+
   // Calculates the item views' bounds for non-folder.
   virtual void CalculateIdealBounds();
 
   // Calculates the item views' bounds for folder.
   void CalculateIdealBoundsForFolder();
 
+  // Update the padding of tile view based on the contents bounds.
+  void UpdateTilePadding();
+
   // Gets the bounds of the tile located at |index|, where |index| contains the
   // page/slot info.
   gfx::Rect GetExpectedTileBounds(const GridIndex& index) const;
@@ -392,11 +404,6 @@
   // zone or is over page switcher.
   void MaybeStartPageFlipTimer(const gfx::Point& drag_point);
 
-  // Creates a layer mask for gradient alpha when the feature is enabled.
-  // TODO(crbug.com/1211608): Move to PagedAppsGridView when
-  // `fadeout_layer_delegate_` moves.
-  void MaybeCreateGradientMask();
-
   bool ignore_layout() const { return ignore_layout_; }
   views::BoundsAnimator* bounds_animator() { return bounds_animator_.get(); }
   views::View* items_container() { return items_container_; }
@@ -429,7 +436,13 @@
   // The location of |drag_view_| when the drag started.
   gfx::Point drag_view_start_;
 
-  std::unique_ptr<FadeoutLayerDelegate> fadeout_layer_delegate_;
+  // True if the AppList is in cardified state.
+  // TODO(crbug.com/1211608): Move cardified state members to PagedAppsGridView.
+  bool cardified_state_ = false;
+
+  // Layer array for apps grid background cards. Used to display the background
+  // card during cardified state.
+  std::vector<std::unique_ptr<ui::Layer>> background_cards_;
 
  private:
   friend class test::AppsGridViewTestApi;
@@ -730,9 +743,6 @@
   // histograms.
   void RecordAppMovingTypeMetrics(AppListAppMovingType type);
 
-  // Update the padding of tile view based on the contents bounds.
-  void UpdateTilePadding();
-
   // Starts the animation to transition the |drag_item| from |source_bounds| to
   // the target bounds in the |folder_item_view|. Note that this animation
   // should run only after |drag_item| is added to the folder.
@@ -917,21 +927,12 @@
   // If true, Layout() does nothing. See where set for details.
   bool ignore_layout_ = false;
 
-  // True if the AppList is in cardified state.
-  bool cardified_state_ = false;
-
   // The highlighted page during cardified state.
   int highlighted_page_ = -1;
 
-  // Layer array for apps grid background cards. Used to display the background
-  // card during cardified state.
-  std::vector<std::unique_ptr<ui::Layer>> background_cards_;
-
   int bounds_animation_for_cardified_state_in_progress_ = 0;
 
   base::WeakPtrFactory<AppsGridView> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(AppsGridView);
 };
 
 }  // namespace ash
diff --git a/ash/app_list/views/paged_apps_grid_view.cc b/ash/app_list/views/paged_apps_grid_view.cc
index 61517620..3ae00b6e 100644
--- a/ash/app_list/views/paged_apps_grid_view.cc
+++ b/ash/app_list/views/paged_apps_grid_view.cc
@@ -10,21 +10,29 @@
 #include "ash/app_list/views/app_list_main_view.h"
 #include "ash/app_list/views/contents_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
+#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/pagination/pagination_controller.h"
 #include "ash/public/cpp/pagination/pagination_model.h"
 #include "base/check.h"
 #include "base/metrics/histogram_macros.h"
+#include "cc/paint/paint_flags.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/paint_recorder.h"
 #include "ui/events/event.h"
 #include "ui/events/types/event_type.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/transform.h"
+#include "ui/views/paint_info.h"
 #include "ui/views/view.h"
+#include "ui/views/view_model_utils.h"
 
 namespace ash {
 namespace {
@@ -43,6 +51,67 @@
 
 }  // namespace
 
+// A layer delegate used for PagedAppsGridView's mask layer, with top and bottom
+// gradient fading out zones.
+class PagedAppsGridView::FadeoutLayerDelegate : public ui::LayerDelegate {
+ public:
+  explicit FadeoutLayerDelegate(int fadeout_mask_height)
+      : layer_(ui::LAYER_TEXTURED), fadeout_mask_height_(fadeout_mask_height) {
+    layer_.set_delegate(this);
+    layer_.SetFillsBoundsOpaquely(false);
+  }
+  FadeoutLayerDelegate(const FadeoutLayerDelegate&) = delete;
+  FadeoutLayerDelegate& operator=(const FadeoutLayerDelegate&) = delete;
+
+  ~FadeoutLayerDelegate() override { layer_.set_delegate(nullptr); }
+
+  ui::Layer* layer() { return &layer_; }
+
+ private:
+  // ui::LayerDelegate:
+  // TODO(warx): using a mask is expensive. It would be more efficient to avoid
+  // the mask for the central area and only use it for top/bottom areas.
+  void OnPaintLayer(const ui::PaintContext& context) override {
+    const gfx::Size size = layer()->size();
+    gfx::Rect top_rect(0, 0, size.width(), fadeout_mask_height_);
+    gfx::Rect bottom_rect(0, size.height() - fadeout_mask_height_, size.width(),
+                          fadeout_mask_height_);
+
+    views::PaintInfo paint_info =
+        views::PaintInfo::CreateRootPaintInfo(context, size);
+    const auto& prs = paint_info.paint_recording_size();
+
+    //  Pass the scale factor when constructing PaintRecorder so the MaskLayer
+    //  size is not incorrectly rounded (see https://crbug.com/921274).
+    ui::PaintRecorder recorder(context, paint_info.paint_recording_size(),
+                               static_cast<float>(prs.width()) / size.width(),
+                               static_cast<float>(prs.height()) / size.height(),
+                               nullptr);
+
+    gfx::Canvas* canvas = recorder.canvas();
+    // Clear the canvas.
+    canvas->DrawColor(SK_ColorBLACK, SkBlendMode::kSrc);
+    // Draw top gradient zone.
+    cc::PaintFlags flags;
+    flags.setBlendMode(SkBlendMode::kSrc);
+    flags.setAntiAlias(false);
+    flags.setShader(gfx::CreateGradientShader(
+        gfx::Point(), gfx::Point(0, fadeout_mask_height_), SK_ColorTRANSPARENT,
+        SK_ColorBLACK));
+    canvas->DrawRect(top_rect, flags);
+    // Draw bottom gradient zone.
+    flags.setShader(gfx::CreateGradientShader(
+        gfx::Point(0, size.height() - fadeout_mask_height_),
+        gfx::Point(0, size.height()), SK_ColorBLACK, SK_ColorTRANSPARENT));
+    canvas->DrawRect(bottom_rect, flags);
+  }
+  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
+                                  float new_device_scale_factor) override {}
+
+  ui::Layer layer_;
+  const int fadeout_mask_height_;
+};
+
 PagedAppsGridView::PagedAppsGridView(
     ContentsView* contents_view,
     AppsGridViewFolderDelegate* folder_delegate)
@@ -263,8 +332,76 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// views::View:
+
+void PagedAppsGridView::Layout() {
+  if (ignore_layout())
+    return;
+
+  if (bounds_animator()->IsAnimating())
+    bounds_animator()->Cancel();
+
+  if (GetContentsBounds().IsEmpty())
+    return;
+
+  // Update cached tile padding first, as grid size calculations depend on the
+  // cached padding value.
+  UpdateTilePadding();
+
+  // Prepare |page_size| * number-of-pages for |items_container_|, and sets the
+  // origin properly to show the correct page.
+  const gfx::Size page_size = GetTileGridSize();
+  const int pages = pagination_model_.total_pages();
+  const int current_page = pagination_model_.selected_page();
+  if (pagination_controller_->scroll_axis() ==
+      PaginationController::SCROLL_AXIS_HORIZONTAL) {
+    const int page_width = page_size.width() + GetPaddingBetweenPages();
+    items_container()->SetBoundsRect(gfx::Rect(-page_width * current_page, 0,
+                                               page_width * pages,
+                                               GetContentsBounds().height()));
+  } else {
+    const int page_height = page_size.height() + GetPaddingBetweenPages();
+    items_container()->SetBoundsRect(gfx::Rect(0, -page_height * current_page,
+                                               GetContentsBounds().width(),
+                                               page_height * pages));
+  }
+
+  if (fadeout_layer_delegate_)
+    fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
+
+  CalculateIdealBoundsForFolder();
+  for (int i = 0; i < view_model()->view_size(); ++i) {
+    AppListItemView* view = GetItemViewAt(i);
+    if (view != drag_view_) {
+      view->SetBoundsRect(view_model()->ideal_bounds(i));
+    } else {
+      // If the drag view size changes, make sure it has the same center.
+      gfx::Rect bounds = view->bounds();
+      bounds.ClampToCenteredSize(GetTileViewSize());
+      view->SetBoundsRect(bounds);
+    }
+  }
+  if (cardified_state_) {
+    DCHECK(!background_cards_.empty());
+    MaybeCreateGradientMask();
+    // Make sure that the background cards render behind everything
+    // else in the items container.
+    for (auto& background_card : background_cards_)
+      items_container()->layer()->StackAtBottom(background_card.get());
+  }
+  views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model());
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // AppsGridView:
 
+gfx::Size PagedAppsGridView::GetTileViewSize() const {
+  const AppListConfig& config = GetAppListConfig();
+  return gfx::ScaleToRoundedSize(
+      gfx::Size(config.grid_tile_width(), config.grid_tile_height()),
+      (cardified_state_ ? kCardifiedScale : 1.0f));
+}
+
 gfx::Insets PagedAppsGridView::GetTilePadding() const {
   if (is_in_folder()) {
     const int tile_padding_in_folder =
@@ -282,6 +419,24 @@
   return rect.size();
 }
 
+void PagedAppsGridView::MaybeCreateGradientMask() {
+  if (!is_in_folder() && features::IsBackgroundBlurEnabled()) {
+    // TODO(newcomer): Improve implementation of the mask layer so we can
+    // enable it on all devices https://crbug.com/765292.
+    if (!layer()->layer_mask_layer()) {
+      // Always create a new layer. The layer may be recreated by animation,
+      // and using the mask layer used by the detached layer can lead to
+      // crash. b/118822974.
+      if (!fadeout_layer_delegate_) {
+        fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>(
+            GetAppListConfig().grid_fadeout_mask_height());
+        fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
+      }
+      layer()->SetMaskLayer(fadeout_layer_delegate_->layer());
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // PaginationModelObserver:
 
diff --git a/ash/app_list/views/paged_apps_grid_view.h b/ash/app_list/views/paged_apps_grid_view.h
index 1db3fe51..3c52026 100644
--- a/ash/app_list/views/paged_apps_grid_view.h
+++ b/ash/app_list/views/paged_apps_grid_view.h
@@ -49,9 +49,14 @@
   void OnGestureEvent(ui::GestureEvent* event) override;
   void OnMouseEvent(ui::MouseEvent* event) override;
 
+  // views::View:
+  void Layout() override;
+
   // AppsGridView:
+  gfx::Size GetTileViewSize() const override;
   gfx::Insets GetTilePadding() const override;
   gfx::Size GetTileGridSize() const override;
+  void MaybeCreateGradientMask() override;
 
   // PaginationModelObserver:
   void TotalPagesChanged(int previous_page_count, int new_page_count) override;
@@ -64,6 +69,8 @@
   void ScrollEnded() override;
 
  private:
+  class FadeoutLayerDelegate;
+
   // Indicates whether the drag event (from the gesture or mouse) should be
   // handled by PagedAppsGridView.
   bool ShouldHandleDragEvent(const ui::LocatedEvent& event);
@@ -84,6 +91,10 @@
   // between-item drags that move the entire grid, not for app icon drags.
   gfx::PointF last_mouse_drag_point_;
 
+  // Implements a "fade out" gradient at the top and bottom of the grid. Used
+  // during page flip transitions and for cardified drags.
+  std::unique_ptr<FadeoutLayerDelegate> fadeout_layer_delegate_;
+
   // Records smoothness of pagination animation.
   absl::optional<ui::ThroughputTracker> pagination_metrics_tracker_;
 
diff --git a/ash/components/account_manager/access_token_fetcher.cc b/ash/components/account_manager/access_token_fetcher.cc
index 58f72bff..c15ad925 100644
--- a/ash/components/account_manager/access_token_fetcher.cc
+++ b/ash/components/account_manager/access_token_fetcher.cc
@@ -94,6 +94,11 @@
   DCHECK(callback_.is_null())
       << "Finish called before responding to pending request";
 
+  // If `OnMojoPipeError` is called after `OnGetTokenSuccess` or
+  // `OnGetTokenFailure`, the `done_callback_` will be null.
+  if (done_callback_.is_null())
+    return;
+
   // We cannot call `TriggerDeletion` directly because it will immediately start
   // deleting `this`, before this method has had a chance to return.
   base::SequencedTaskRunnerHandle::Get()->PostTask(
diff --git a/ash/components/resources/BUILD.gn b/ash/components/resources/BUILD.gn
index 1ade922c..d2698f9 100644
--- a/ash/components/resources/BUILD.gn
+++ b/ash/components/resources/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//ash/content/help_app_ui/help_app_ui.gni")
 import("//tools/grit/grit_rule.gni")
 
 assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //ash")
@@ -49,65 +48,6 @@
   }
 }
 
-# Resources used by chrome://help-app, and parts of the sandboxed app it hosts
-# that do not come from the app bundle (below).
-grit("help_app_resources") {
-  source = "../../content/help_app_ui/resources/help_app_resources.grd"
-
-  outputs = [
-    "grit/ash_help_app_resources.h",
-    "grit/ash_help_app_resources_map.cc",
-    "grit/ash_help_app_resources_map.h",
-    "ash_help_app_resources.pak",
-  ]
-  output_dir = "$root_gen_dir/ash"
-
-  deps = [
-    "//ash/content/help_app_ui:mojo_bindings_js",
-    "//ash/content/help_app_ui/search:mojo_bindings_js",
-    "//chromeos/components/local_search_service/public/mojom:mojom_js",
-  ]
-}
-
-# Resources automatically served by the chrome://help-app bundle, obtained via DEPS.
-grit("help_app_bundle_resources") {
-  if (enable_cros_help_app) {
-    # Obtained via an internal CIPD package in src/DEPS.
-    source =
-        "../../content/help_app_ui/resources/prod/help_app_bundle_resources.grd"
-  } else {
-    source = "../../content/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd"
-  }
-
-  use_brotli = true
-
-  outputs = [
-    "grit/ash_help_app_bundle_resources.h",
-    "grit/ash_help_app_bundle_resources_map.cc",
-    "grit/ash_help_app_bundle_resources_map.h",
-    "ash_help_app_bundle_resources.pak",
-  ]
-  output_dir = "$root_gen_dir/ash"
-}
-
-grit("help_app_kids_magazine_bundle_resources") {
-  if (enable_cros_help_app) {
-    source = "../../content/help_app_ui/resources/prod/help_app_kids_magazine_bundle_resources.grd"
-  } else {
-    source = "../../content/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd"
-  }
-
-  use_brotli = true
-
-  outputs = [
-    "grit/ash_help_app_kids_magazine_bundle_resources.h",
-    "grit/ash_help_app_kids_magazine_bundle_resources_map.cc",
-    "grit/ash_help_app_kids_magazine_bundle_resources_map.h",
-    "ash_help_app_kids_magazine_bundle_resources.pak",
-  ]
-  output_dir = "$root_gen_dir/ash"
-}
-
 grit("scanning_app_resources") {
   source = "../../content/scanning/resources/scanning_app_resources.grd"
 
diff --git a/ash/content/BUILD.gn b/ash/content/BUILD.gn
index f5fc377..ef6f411 100644
--- a/ash/content/BUILD.gn
+++ b/ash/content/BUILD.gn
@@ -17,12 +17,10 @@
   ]
 
   deps = [
-    "//ash/content/help_app_ui:unit_tests",
     "//ash/content/scanning:unit_tests",
     "//base",
     "//base/test:test_support",
     "//build:chromeos_buildflags",
-    "//mojo/core/embedder",
     "//ui/base:base",
   ]
 
@@ -35,7 +33,6 @@
 group("closure_compile") {
   testonly = true
   deps = [
-    "//ash/content/help_app_ui:closure_compile",
     "//ash/content/scanning:closure_compile",
     "//ash/content/shimless_rma:closure_compile",
     "//ash/content/shortcut_customization_ui:closure_compile",
diff --git a/ash/content/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd b/ash/content/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
deleted file mode 100644
index ea90f2cd..0000000
--- a/ash/content/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit current_release="1" latest_public_release="0" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/ash_help_app_bundle_resources.h" type="rc_header">
-      <emit emit_type="prepend"/>
-    </output>
-    <output filename="grit/ash_help_app_bundle_resources_map.cc" type="resource_file_map_source"/>
-    <output filename="grit/ash_help_app_bundle_resources_map.h" type="resource_map_header"/>
-    <output filename="ash_help_app_bundle_resources.pak" type="data_package"/>
-  </outputs>
-  <release seq="1">
-    <includes>
-      <include name="IDR_HELP_APP_APP_BIN_JS" file="app_bin.js" type="BINDATA" />
-    </includes>
-  </release>
-</grit>
diff --git a/ash/content/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd b/ash/content/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd
deleted file mode 100644
index eb0d4b83..0000000
--- a/ash/content/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit current_release="1" latest_public_release="0" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/ash_help_app_kids_magazine_bundle_resources.h" type="rc_header">
-      <emit emit_type="prepend"/>
-    </output>
-    <output filename="grit/ash_help_app_kids_magazine_bundle_resources_map.cc" type="resource_file_map_source"/>
-    <output filename="grit/ash_help_app_kids_magazine_bundle_resources_map.h" type="resource_map_header"/>
-    <output filename="ash_help_app_kids_magazine_bundle_resources.pak" type="data_package"/>
-  </outputs>
-  <release seq="1">
-    <includes>
-      <include name="IDR_HELP_APP_KIDS_MAGAZINE_INDEX_HTML" file="index.html" type="BINDATA" />
-    </includes>
-  </release>
-</grit>
diff --git a/ash/content/run_all_unittests.cc b/ash/content/run_all_unittests.cc
index 8be2629..73aa9bb 100644
--- a/ash/content/run_all_unittests.cc
+++ b/ash/content/run_all_unittests.cc
@@ -7,7 +7,6 @@
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "build/chromeos_buildflags.h"
-#include "mojo/core/embedder/embedder.h"
 
 #if BUILDFLAG(IS_CHROMEOS_DEVICE)
 #error This test target only builds with linux-chromeos, not for real ChromeOS\
@@ -15,9 +14,6 @@
 #endif
 
 int main(int argc, char** argv) {
-  // Some unit tests make Mojo calls.
-  mojo::core::Init();
-
   AshContentTestSuite test_suite(argc, argv);
   return base::LaunchUnitTests(
       argc, argv,
diff --git a/ash/display/display_move_window_util_unittest.cc b/ash/display/display_move_window_util_unittest.cc
index 00f6863..eaf3e8b 100644
--- a/ash/display/display_move_window_util_unittest.cc
+++ b/ash/display/display_move_window_util_unittest.cc
@@ -132,7 +132,7 @@
 
   // Set window to left snapped state.
   PerformMoveWindowAccel();
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
             screen->GetDisplayNearestWindow(window).id());
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index 9f5015a..9121b6e 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -215,7 +215,7 @@
   generator->MoveMouseTo(CenterPointInScreen(close_button()));
   generator->ReleaseLeftButton();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kRightSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kSecondarySnapped));
 
   // Snap left.
   generator->MoveMouseTo(CenterPointInScreen(size_button()));
@@ -223,7 +223,7 @@
   generator->MoveMouseTo(CenterPointInScreen(minimize_button()));
   generator->ReleaseLeftButton();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kLeftSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kPrimarySnapped));
 
   // 2) Test with scroll gestures.
   // Snap right.
@@ -231,14 +231,14 @@
                                    CenterPointInScreen(close_button()),
                                    base::TimeDelta::FromMilliseconds(100), 3);
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kRightSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kSecondarySnapped));
 
   // Snap left.
   generator->GestureScrollSequence(CenterPointInScreen(size_button()),
                                    CenterPointInScreen(minimize_button()),
                                    base::TimeDelta::FromMilliseconds(100), 3);
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kLeftSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kPrimarySnapped));
 
   // 3) Test with tap gestures.
   const float touch_default_radius =
@@ -248,12 +248,12 @@
   generator->MoveMouseTo(CenterPointInScreen(size_button()));
   generator->PressMoveAndReleaseTouchTo(CenterPointInScreen(close_button()));
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kRightSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kSecondarySnapped));
   // Snap left.
   generator->MoveMouseTo(CenterPointInScreen(size_button()));
   generator->PressMoveAndReleaseTouchTo(CenterPointInScreen(minimize_button()));
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kLeftSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kPrimarySnapped));
   ui::GestureConfiguration::GetInstance()->set_default_radius(
       touch_default_radius);
 }
@@ -273,7 +273,7 @@
   generator->MoveMouseBy(-minimize_button()->width(), 0);
   generator->ReleaseLeftButton();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kLeftSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kPrimarySnapped));
 }
 
 // Test that right clicking the size button has no effect.
@@ -360,7 +360,7 @@
   // Release the mouse, snapping the window left.
   generator->ReleaseLeftButton();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kLeftSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kPrimarySnapped));
 
   // None of the buttons should stay pressed and the buttons should have their
   // regular icons.
@@ -396,7 +396,7 @@
   // Release the mouse. The window should stay snapped left.
   generator->ReleaseLeftButton();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kLeftSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kPrimarySnapped));
 
   // The buttons should stay unpressed and the buttons should now have their
   // regular icons.
@@ -505,7 +505,7 @@
   // Releasing should snap the window right.
   generator->ReleaseLeftButton();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasStateType(WindowStateType::kRightSnapped));
+  EXPECT_TRUE(HasStateType(WindowStateType::kSecondarySnapped));
 
   // None of the buttons should stay pressed and the buttons should have their
   // regular icons.
diff --git a/ash/frame/snap_controller_impl.cc b/ash/frame/snap_controller_impl.cc
index 28f24c14..97190cee 100644
--- a/ash/frame/snap_controller_impl.cc
+++ b/ash/frame/snap_controller_impl.cc
@@ -48,8 +48,8 @@
 
   WindowState* window_state = WindowState::Get(window);
   const WMEvent snap_event(snap == chromeos::SnapDirection::kLeft
-                               ? WM_EVENT_SNAP_LEFT
-                               : WM_EVENT_SNAP_RIGHT);
+                               ? WM_EVENT_SNAP_PRIMARY
+                               : WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_event);
 }
 
diff --git a/ash/login/ui/animated_rounded_image_view.cc b/ash/login/ui/animated_rounded_image_view.cc
index bfb4f03..1354083 100644
--- a/ash/login/ui/animated_rounded_image_view.cc
+++ b/ash/login/ui/animated_rounded_image_view.cc
@@ -21,8 +21,7 @@
 class SingleFrameImageDecoder
     : public AnimatedRoundedImageView::AnimationDecoder {
  public:
-  explicit SingleFrameImageDecoder(const gfx::ImageSkia& image)
-      : image_(image) {}
+  SingleFrameImageDecoder(const gfx::ImageSkia& image) : image_(image) {}
   ~SingleFrameImageDecoder() override = default;
 
   // AnimatedRoundedImageView::AnimationDecoder:
diff --git a/ash/login/ui/bottom_status_indicator.h b/ash/login/ui/bottom_status_indicator.h
index e5ac791..c0487e0 100644
--- a/ash/login/ui/bottom_status_indicator.h
+++ b/ash/login/ui/bottom_status_indicator.h
@@ -20,7 +20,7 @@
  public:
   using TappedCallback = base::RepeatingClosure;
 
-  explicit BottomStatusIndicator(TappedCallback on_tapped_callback);
+  BottomStatusIndicator(TappedCallback on_tapped_callback);
   BottomStatusIndicator(const BottomStatusIndicator&) = delete;
   BottomStatusIndicator& operator=(const BottomStatusIndicator&) = delete;
   ~BottomStatusIndicator() override;
diff --git a/ash/login/ui/login_base_bubble_view.cc b/ash/login/ui/login_base_bubble_view.cc
index d2776a7..e64deee 100644
--- a/ash/login/ui/login_base_bubble_view.cc
+++ b/ash/login/ui/login_base_bubble_view.cc
@@ -47,7 +47,7 @@
 // associated bubble in response.
 class LoginBubbleHandler : public ui::EventHandler {
  public:
-  explicit LoginBubbleHandler(LoginBaseBubbleView* bubble) : bubble_(bubble) {
+  LoginBubbleHandler(LoginBaseBubbleView* bubble) : bubble_(bubble) {
     Shell::Get()->AddPreTargetHandler(this);
   }
 
diff --git a/ash/login/ui/login_user_view.cc b/ash/login/ui/login_user_view.cc
index df220e66..e9504de 100644
--- a/ash/login/ui/login_user_view.cc
+++ b/ash/login/ui/login_user_view.cc
@@ -88,7 +88,7 @@
 class PassthroughAnimationDecoder
     : public AnimatedRoundedImageView::AnimationDecoder {
  public:
-  explicit PassthroughAnimationDecoder(const AnimationFrames& frames)
+  PassthroughAnimationDecoder(const AnimationFrames& frames)
       : frames_(frames) {}
   ~PassthroughAnimationDecoder() override = default;
 
@@ -102,7 +102,7 @@
 
 class IconRoundedView : public views::View {
  public:
-  explicit IconRoundedView(int size) : size_(size) {}
+  IconRoundedView(int size) : size_(size) {}
   ~IconRoundedView() override = default;
 
   IconRoundedView(const IconRoundedView&) = delete;
@@ -166,7 +166,7 @@
     LoginUserView::UserImage* const view_;
   };
 
-  explicit UserImage(LoginDisplayStyle style)
+  UserImage(LoginDisplayStyle style)
       : NonAccessibleView(kLoginUserImageClassName) {
     SetLayoutManager(std::make_unique<views::FillLayout>());
 
diff --git a/ash/login/ui/public_account_warning_dialog.h b/ash/login/ui/public_account_warning_dialog.h
index b1042cb..189d3461 100644
--- a/ash/login/ui/public_account_warning_dialog.h
+++ b/ash/login/ui/public_account_warning_dialog.h
@@ -17,7 +17,7 @@
 // clicks on the learn more link on the pubic account expanded view.
 class ASH_EXPORT PublicAccountWarningDialog : public views::DialogDelegateView {
  public:
-  explicit PublicAccountWarningDialog(
+  PublicAccountWarningDialog(
       base::WeakPtr<LoginExpandedPublicAccountView> controller);
   ~PublicAccountWarningDialog() override;
 
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc
index 382989d..4a30a5ff2 100644
--- a/ash/metrics/user_metrics_recorder.cc
+++ b/ash/metrics/user_metrics_recorder.cc
@@ -60,8 +60,8 @@
       case WindowStateType::kFullscreen:
         active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_FULLSCREEN;
         break;
-      case WindowStateType::kLeftSnapped:
-      case WindowStateType::kRightSnapped:
+      case WindowStateType::kPrimarySnapped:
+      case WindowStateType::kSecondarySnapped:
         active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_SNAPPED;
         break;
       case WindowStateType::kPinned:
diff --git a/ash/public/cpp/holding_space/BUILD.gn b/ash/public/cpp/holding_space/BUILD.gn
new file mode 100644
index 0000000..fa9e064e
--- /dev/null
+++ b/ash/public/cpp/holding_space/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2021 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.
+
+source_set("test_support") {
+  testonly = true
+
+  sources = [
+    "mock_holding_space_client.cc",
+    "mock_holding_space_client.h",
+    "mock_holding_space_model_observer.cc",
+    "mock_holding_space_model_observer.h",
+  ]
+
+  deps = [
+    "//ash/public/cpp",
+    "//testing/gmock",
+  ]
+}
diff --git a/ash/public/cpp/holding_space/holding_space_client.h b/ash/public/cpp/holding_space/holding_space_client.h
index 56f45c1..fc9a0c16 100644
--- a/ash/public/cpp/holding_space/holding_space_client.h
+++ b/ash/public/cpp/holding_space/holding_space_client.h
@@ -31,7 +31,9 @@
   // Adds a screen recording item backed by the provided `file_path`.
   virtual void AddScreenRecording(const base::FilePath& file_path) = 0;
 
-  // Attempts to cancel the specified holding space `items`.
+  // Attempts to cancel the specified in-progress holding space `items`. In the
+  // case of in-progress holding space downloads, this would attempt to cancel
+  // the underlying download which would subsequently result in item removal.
   virtual void CancelItems(
       const std::vector<const HoldingSpaceItem*>& items) = 0;
 
@@ -59,10 +61,11 @@
   // Success is returned via the supplied `callback`.
   virtual void OpenMyFiles(SuccessCallback callback) = 0;
 
-  // Attempts to show the specified holding space `item` in its folder.
-  // Success is returned via the supplied `callback`.
-  virtual void ShowItemInFolder(const HoldingSpaceItem& item,
-                                SuccessCallback callback) = 0;
+  // Attempts to pause progress of the specified in-progress holding space
+  // `items`. In the case of in-progress holding space downloads, this would
+  // attempt to pause the underlying download.
+  virtual void PauseItems(
+      const std::vector<const HoldingSpaceItem*>& items) = 0;
 
   // Pins the specified `file_paths`.
   virtual void PinFiles(const std::vector<base::FilePath>& file_paths) = 0;
@@ -70,6 +73,17 @@
   // Pins the specified holding space `items`.
   virtual void PinItems(const std::vector<const HoldingSpaceItem*>& items) = 0;
 
+  // Attempts to resume progress of the specified in-progress holding space
+  // `items`. In the case of in-progress holding space downloads, this would
+  // attempt to resume the underlying download.
+  virtual void ResumeItems(
+      const std::vector<const HoldingSpaceItem*>& items) = 0;
+
+  // Attempts to show the specified holding space `item` in its folder.
+  // Success is returned via the supplied `callback`.
+  virtual void ShowItemInFolder(const HoldingSpaceItem& item,
+                                SuccessCallback callback) = 0;
+
   // Unpins the specified holding space `items`.
   virtual void UnpinItems(
       const std::vector<const HoldingSpaceItem*>& items) = 0;
diff --git a/ash/public/cpp/holding_space/holding_space_constants.h b/ash/public/cpp/holding_space/holding_space_constants.h
index ed4cadb..b5295b2 100644
--- a/ash/public/cpp/holding_space/holding_space_constants.h
+++ b/ash/public/cpp/holding_space/holding_space_constants.h
@@ -37,6 +37,8 @@
   kCopyImageToClipboard,
   kHidePreviews,
   kRemoveItem,
+  kResumeItem,
+  kPauseItem,
   kPinItem,
   kShowInFolder,
   kShowPreviews,
diff --git a/ash/public/cpp/holding_space/mock_holding_space_client.cc b/ash/public/cpp/holding_space/mock_holding_space_client.cc
new file mode 100644
index 0000000..fa80281a
--- /dev/null
+++ b/ash/public/cpp/holding_space/mock_holding_space_client.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 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 "ash/public/cpp/holding_space/mock_holding_space_client.h"
+
+namespace ash {
+
+MockHoldingSpaceClient::MockHoldingSpaceClient() = default;
+MockHoldingSpaceClient::~MockHoldingSpaceClient() = default;
+
+}  // namespace ash
diff --git a/ash/public/cpp/holding_space/mock_holding_space_client.h b/ash/public/cpp/holding_space/mock_holding_space_client.h
new file mode 100644
index 0000000..5bdd725
--- /dev/null
+++ b/ash/public/cpp/holding_space/mock_holding_space_client.h
@@ -0,0 +1,81 @@
+// Copyright 2021 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 ASH_PUBLIC_CPP_HOLDING_SPACE_MOCK_HOLDING_SPACE_CLIENT_H_
+#define ASH_PUBLIC_CPP_HOLDING_SPACE_MOCK_HOLDING_SPACE_CLIENT_H_
+
+#include <vector>
+
+#include "ash/public/cpp/holding_space/holding_space_client.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace ash {
+
+// A mock implementation of `HoldingSpaceClient` for use in testing.
+class MockHoldingSpaceClient : public HoldingSpaceClient {
+ public:
+  MockHoldingSpaceClient();
+  MockHoldingSpaceClient(const MockHoldingSpaceClient&) = delete;
+  MockHoldingSpaceClient& operator=(const MockHoldingSpaceClient&) = delete;
+  ~MockHoldingSpaceClient() override;
+
+  // HoldingSpaceClient:
+  MOCK_METHOD(void,
+              AddScreenshot,
+              (const base::FilePath& file_path),
+              (override));
+  MOCK_METHOD(void,
+              AddScreenRecording,
+              (const base::FilePath& file_path),
+              (override));
+  MOCK_METHOD(void,
+              CancelItems,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+  MOCK_METHOD(void,
+              CopyImageToClipboard,
+              (const HoldingSpaceItem& item, SuccessCallback callback),
+              (override));
+  MOCK_METHOD(base::FilePath,
+              CrackFileSystemUrl,
+              (const GURL& file_system_url),
+              (const, override));
+  MOCK_METHOD(void, OpenDownloads, (SuccessCallback callback), (override));
+  MOCK_METHOD(void, OpenMyFiles, (SuccessCallback callback), (override));
+  MOCK_METHOD(void,
+              OpenItems,
+              (const std::vector<const HoldingSpaceItem*>& items,
+               SuccessCallback callback),
+              (override));
+  MOCK_METHOD(void,
+              PauseItems,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+  MOCK_METHOD(void,
+              PinFiles,
+              (const std::vector<base::FilePath>& file_paths),
+              (override));
+  MOCK_METHOD(void,
+              PinItems,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+  MOCK_METHOD(void,
+              ResumeItems,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+  MOCK_METHOD(void,
+              ShowItemInFolder,
+              (const HoldingSpaceItem& item, SuccessCallback callback),
+              (override));
+  MOCK_METHOD(void,
+              UnpinItems,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_HOLDING_SPACE_MOCK_HOLDING_SPACE_CLIENT_H_
diff --git a/ash/public/cpp/holding_space/mock_holding_space_model_observer.cc b/ash/public/cpp/holding_space/mock_holding_space_model_observer.cc
new file mode 100644
index 0000000..f3dd8df
--- /dev/null
+++ b/ash/public/cpp/holding_space/mock_holding_space_model_observer.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 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 "ash/public/cpp/holding_space/mock_holding_space_model_observer.h"
+
+namespace ash {
+
+MockHoldingSpaceModelObserver::MockHoldingSpaceModelObserver() = default;
+MockHoldingSpaceModelObserver::~MockHoldingSpaceModelObserver() = default;
+
+}  // namespace ash
diff --git a/ash/public/cpp/holding_space/mock_holding_space_model_observer.h b/ash/public/cpp/holding_space/mock_holding_space_model_observer.h
new file mode 100644
index 0000000..6b06cbf
--- /dev/null
+++ b/ash/public/cpp/holding_space/mock_holding_space_model_observer.h
@@ -0,0 +1,45 @@
+// Copyright 2021 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 ASH_PUBLIC_CPP_HOLDING_SPACE_MOCK_HOLDING_SPACE_MODEL_OBSERVER_H_
+#define ASH_PUBLIC_CPP_HOLDING_SPACE_MOCK_HOLDING_SPACE_MODEL_OBSERVER_H_
+
+#include <vector>
+
+#include "ash/public/cpp/holding_space/holding_space_model_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace ash {
+
+// A mock implementation of `HoldingSpaceModelObserver` for use in testing.
+class MockHoldingSpaceModelObserver : public HoldingSpaceModelObserver {
+ public:
+  MockHoldingSpaceModelObserver();
+  MockHoldingSpaceModelObserver(const MockHoldingSpaceModelObserver&) = delete;
+  MockHoldingSpaceModelObserver& operator=(
+      const MockHoldingSpaceModelObserver&) = delete;
+  ~MockHoldingSpaceModelObserver() override;
+
+  // HoldingSpaceModelObserver:
+  MOCK_METHOD(void,
+              OnHoldingSpaceItemsAdded,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+  MOCK_METHOD(void,
+              OnHoldingSpaceItemsRemoved,
+              (const std::vector<const HoldingSpaceItem*>& items),
+              (override));
+  MOCK_METHOD(void,
+              OnHoldingSpaceItemUpdated,
+              (const HoldingSpaceItem* item),
+              (override));
+  MOCK_METHOD(void,
+              OnHoldingSpaceItemInitialized,
+              (const HoldingSpaceItem* item),
+              (override));
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_HOLDING_SPACE_MOCK_HOLDING_SPACE_MODEL_OBSERVER_H_
diff --git a/ash/strings/ash_strings_pa.xtb b/ash/strings/ash_strings_pa.xtb
index bd9f227..acab42ed 100644
--- a/ash/strings/ash_strings_pa.xtb
+++ b/ash/strings/ash_strings_pa.xtb
@@ -526,7 +526,7 @@
 <translation id="5071064518267176975">ਇੱਕ ਐਪ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਵਰਤੋਂ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ</translation>
 <translation id="5075554201838155866">ਬੰਦ ਸੁਰਖੀਆਂ ਸ਼ੁਰੂ ਕਰੋ</translation>
 <translation id="5078796286268621944">ਗ਼ਲਤ PIN</translation>
-<translation id="5083553833479578423">'Assistant' ਦੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਬਾਰੇ ਜਾਣੋ।</translation>
+<translation id="5083553833479578423">'Assistant' ਦੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਅਣਲਾਕ ਕਰੋ।</translation>
 <translation id="5136175204352732067">ਵੱਖਰਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ</translation>
 <translation id="5155897006997040331">ਪੜ੍ਹਨ ਸੰਬੰਧੀ ਗਤੀ</translation>
 <translation id="5168181903108465623">ਕਾਸਟ ਡਿਵਾਈਸਾਂ ਉਪਲਬਧ</translation>
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc
index 881ec876..0c37a9a4 100644
--- a/ash/system/holding_space/holding_space_tray_unittest.cc
+++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -17,6 +17,7 @@
 #include "ash/public/cpp/holding_space/holding_space_model.h"
 #include "ash/public/cpp/holding_space/holding_space_prefs.h"
 #include "ash/public/cpp/holding_space/holding_space_test_api.h"
+#include "ash/public/cpp/holding_space/mock_holding_space_client.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_widget.h"
@@ -127,56 +128,6 @@
       /*async_bitmap_resolver=*/base::DoNothing());
 }
 
-// Mocks -----------------------------------------------------------------------
-
-class MockHoldingSpaceClient : public HoldingSpaceClient {
- public:
-  // HoldingSpaceClient:
-  MOCK_METHOD(void,
-              AddScreenshot,
-              (const base::FilePath& file_path),
-              (override));
-  MOCK_METHOD(void,
-              AddScreenRecording,
-              (const base::FilePath& file_path),
-              (override));
-  MOCK_METHOD(void,
-              CancelItems,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              CopyImageToClipboard,
-              (const HoldingSpaceItem& item, SuccessCallback callback),
-              (override));
-  MOCK_METHOD(base::FilePath,
-              CrackFileSystemUrl,
-              (const GURL& file_system_url),
-              (const, override));
-  MOCK_METHOD(void, OpenDownloads, (SuccessCallback callback), (override));
-  MOCK_METHOD(void, OpenMyFiles, (SuccessCallback callback), (override));
-  MOCK_METHOD(void,
-              OpenItems,
-              (const std::vector<const HoldingSpaceItem*>& items,
-               SuccessCallback callback),
-              (override));
-  MOCK_METHOD(void,
-              ShowItemInFolder,
-              (const HoldingSpaceItem& item, SuccessCallback callback),
-              (override));
-  MOCK_METHOD(void,
-              PinFiles,
-              (const std::vector<base::FilePath>& file_paths),
-              (override));
-  MOCK_METHOD(void,
-              PinItems,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              UnpinItems,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-};
-
 // Waiters ---------------------------------------------------------------------
 
 // A class capable of waiting until a layer has stopped animating.
diff --git a/ash/system/holding_space/holding_space_view_delegate.cc b/ash/system/holding_space/holding_space_view_delegate.cc
index a023c6e..1ea1014 100644
--- a/ash/system/holding_space/holding_space_view_delegate.cc
+++ b/ash/system/holding_space/holding_space_view_delegate.cc
@@ -479,45 +479,46 @@
 }
 
 void HoldingSpaceViewDelegate::ExecuteCommand(int command_id, int event_flags) {
-  std::vector<const HoldingSpaceItemView*> selection = GetSelection();
-  DCHECK_GE(selection.size(), 1u);
+  const std::vector<const HoldingSpaceItem*> items(GetItems(GetSelection()));
+  DCHECK_GE(items.size(), 1u);
 
+  HoldingSpaceClient* const client = HoldingSpaceController::Get()->client();
   switch (static_cast<HoldingSpaceCommandId>(command_id)) {
     case HoldingSpaceCommandId::kCancelItem:
-      HoldingSpaceController::Get()->client()->CancelItems(GetItems(selection));
+      client->CancelItems(items);
       break;
     case HoldingSpaceCommandId::kCopyImageToClipboard:
-      DCHECK_EQ(selection.size(), 1u);
-      HoldingSpaceController::Get()->client()->CopyImageToClipboard(
-          *selection.front()->item(), base::DoNothing());
+      DCHECK_EQ(items.size(), 1u);
+      client->CopyImageToClipboard(*items.front(), base::DoNothing());
+      break;
+    case HoldingSpaceCommandId::kPauseItem:
+      client->PauseItems(items);
+      break;
+    case HoldingSpaceCommandId::kPinItem:
+      client->PinItems(items);
       break;
     case HoldingSpaceCommandId::kRemoveItem:
       HoldingSpaceController::Get()->model()->RemoveIf(base::BindRepeating(
-          [](const std::vector<const HoldingSpaceItemView*>& selection,
+          [](const std::vector<const HoldingSpaceItem*>& items,
              const HoldingSpaceItem* item) {
-            const bool remove =
-                std::any_of(selection.begin(), selection.end(),
-                            [item](const HoldingSpaceItemView* view) {
-                              return view->item() == item;
-                            });
+            const bool remove = base::Contains(items, item);
             if (remove) {
               holding_space_metrics::RecordItemAction(
                   {item}, holding_space_metrics::ItemAction::kRemove);
             }
             return remove;
           },
-          std::cref(selection)));
+          std::cref(items)));
       break;
-    case HoldingSpaceCommandId::kPinItem:
-      HoldingSpaceController::Get()->client()->PinItems(GetItems(selection));
+    case HoldingSpaceCommandId::kResumeItem:
+      client->ResumeItems(items);
       break;
     case HoldingSpaceCommandId::kShowInFolder:
-      DCHECK_EQ(selection.size(), 1u);
-      HoldingSpaceController::Get()->client()->ShowItemInFolder(
-          *selection.front()->item(), base::DoNothing());
+      DCHECK_EQ(items.size(), 1u);
+      client->ShowItemInFolder(*items.front(), base::DoNothing());
       break;
     case HoldingSpaceCommandId::kUnpinItem:
-      HoldingSpaceController::Get()->client()->UnpinItems(GetItems(selection));
+      client->UnpinItems(items);
       break;
     default:
       NOTREACHED();
@@ -540,21 +541,58 @@
   std::vector<const HoldingSpaceItemView*> selection = GetSelection();
   DCHECK_GE(selection.size(), 1u);
 
-  const bool is_cancelable = std::all_of(selection.begin(), selection.end(),
-                                         [](const HoldingSpaceItemView* view) {
-                                           return view->item()->IsInProgress();
-                                         });
+  bool is_pausable = true;
+  bool is_resumable = true;
+  bool is_cancelable = true;
+  bool is_pinnable = false;
+  bool is_removable = true;
 
-  if (is_cancelable) {
+  HoldingSpaceModel* const model = HoldingSpaceController::Get()->model();
+  for (const HoldingSpaceItemView* view : selection) {
+    const HoldingSpaceItem* item = view->item();
+
+    // The "Pause" command should only be present if *all* of the selected
+    // holding space items are pausable.
+    is_pausable &= item->IsInProgress() && !item->IsPaused();
+
+    // The "Resume" command should only be present if *all* of the selected
+    // holding space items are resumable.
+    is_resumable &= item->IsPaused();
+
     // The "Cancel" command should only be present if *all* of the selected
     // holding space items are cancelable.
+    is_cancelable &= item->IsInProgress();
+
+    // The "Pin" command should be present if *any* selected holding space item
+    // is unpinned. When executing this command, any holding space items that
+    // are already pinned will be ignored.
+    is_pinnable |= !model->ContainsItem(HoldingSpaceItem::Type::kPinnedFile,
+                                        item->file_path());
+
+    // The "Remove" command should only be present if *all* of the selected
+    // holding space items are removable.
+    is_removable &= item->type() != HoldingSpaceItem::Type::kPinnedFile;
+  }
+
+  if (is_pausable) {
+    context_menu_model_->AddItem(
+        static_cast<int>(HoldingSpaceCommandId::kPauseItem), u"[I18N] Pause");
+  }
+
+  if (is_resumable) {
+    context_menu_model_->AddItem(
+        static_cast<int>(HoldingSpaceCommandId::kResumeItem), u"[I18N] Resume");
+  }
+
+  if (is_cancelable) {
     context_menu_model_->AddItem(
         static_cast<int>(HoldingSpaceCommandId::kCancelItem), u"[I18N] Cancel");
-
-    // NOTE: The "Cancel" command is separated from all other commands.
-    context_menu_model_->AddSeparator(ui::MenuSeparatorType::NORMAL_SEPARATOR);
   }
 
+  // The "Pause"/"Resume"/"Cancel" commands are separated from other commands.
+  if (context_menu_model_->GetItemCount())
+    context_menu_model_->AddSeparator(ui::MenuSeparatorType::NORMAL_SEPARATOR);
+
   if (selection.size() == 1u) {
     // The "Show in folder" command should only be present if there is only one
     // holding space item selected.
@@ -583,24 +621,13 @@
     }
   }
 
-  const bool is_any_unpinned = std::any_of(
-      selection.begin(), selection.end(), [](const HoldingSpaceItemView* view) {
-        return !HoldingSpaceController::Get()->model()->ContainsItem(
-            HoldingSpaceItem::Type::kPinnedFile, view->item()->file_path());
-      });
-
-  if (is_any_unpinned) {
-    // The "Pin" command should be present if any selected holding space item is
-    // unpinned. When executing this command, any holding space items that are
-    // already pinned will be ignored.
+  if (is_pinnable) {
     context_menu_model_->AddItemWithIcon(
         static_cast<int>(HoldingSpaceCommandId::kPinItem),
         l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PIN),
         ui::ImageModel::FromVectorIcon(views::kPinIcon, /*color_id=*/-1,
                                        kHoldingSpaceIconSize));
   } else {
-    // The "Unpin" command should be present only if all selected holding space
-    // items are already pinned.
     context_menu_model_->AddItemWithIcon(
         static_cast<int>(HoldingSpaceCommandId::kUnpinItem),
         l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_UNPIN),
@@ -608,11 +635,6 @@
                                        kHoldingSpaceIconSize));
   }
 
-  const bool is_removable = std::all_of(
-      selection.begin(), selection.end(), [](const HoldingSpaceItemView* view) {
-        return view->item()->type() != HoldingSpaceItem::Type::kPinnedFile;
-      });
-
   if (is_removable) {
     context_menu_model_->AddItemWithIcon(
         static_cast<int>(HoldingSpaceCommandId::kRemoveItem),
diff --git a/ash/wm/README.md b/ash/wm/README.md
index c67d9bf..4feef80 100644
--- a/ash/wm/README.md
+++ b/ash/wm/README.md
@@ -45,7 +45,7 @@
 #include "ash/wm/window_state.h"
 
 WindowState* window_state = WindowState::Get(window);
-WMEvent wm_event(WM_EVENT_SNAP_LEFT);
+WMEvent wm_event(WM_EVENT_SNAP_PRIMARY);
 window_state->OnWMEvent(&wm_event);
 // WindowState will compute the animation and target bounds and animate the
 // window to the left half.
diff --git a/ash/wm/base_state.cc b/ash/wm/base_state.cc
index 31f6058d..6550386 100644
--- a/ash/wm/base_state.cc
+++ b/ash/wm/base_state.cc
@@ -68,10 +68,10 @@
       return WindowStateType::kMinimized;
     case WM_EVENT_FULLSCREEN:
       return WindowStateType::kFullscreen;
-    case WM_EVENT_SNAP_LEFT:
-      return WindowStateType::kLeftSnapped;
-    case WM_EVENT_SNAP_RIGHT:
-      return WindowStateType::kRightSnapped;
+    case WM_EVENT_SNAP_PRIMARY:
+      return WindowStateType::kPrimarySnapped;
+    case WM_EVENT_SNAP_SECONDARY:
+      return WindowStateType::kSecondarySnapped;
     case WM_EVENT_SHOW_INACTIVE:
       return WindowStateType::kInactive;
     case WM_EVENT_PIN:
@@ -126,9 +126,9 @@
   // For tablet mode, use |TabletModeWindowState::CycleTabletSnap|.
   DCHECK(!Shell::Get()->tablet_mode_controller()->InTabletMode());
 
-  WindowStateType desired_snap_state = event == WM_EVENT_CYCLE_SNAP_LEFT
-                                           ? WindowStateType::kLeftSnapped
-                                           : WindowStateType::kRightSnapped;
+  WindowStateType desired_snap_state = event == WM_EVENT_CYCLE_SNAP_PRIMARY
+                                           ? WindowStateType::kPrimarySnapped
+                                           : WindowStateType::kSecondarySnapped;
   aura::Window* window = window_state->window();
   // If |window| can be snapped but is not currently in |desired_snap_state|,
   // then snap |window| to the side that corresponds to |desired_snap_state|.
@@ -140,13 +140,13 @@
       // restrictive than |WindowState::CanSnap|.
       DCHECK(SplitViewController::Get(window)->IsWindowInSplitView(window));
       SplitViewController::Get(window)->SnapWindow(
-          window, desired_snap_state == WindowStateType::kLeftSnapped
+          window, desired_snap_state == WindowStateType::kPrimarySnapped
                       ? SplitViewController::LEFT
                       : SplitViewController::RIGHT);
     } else {
-      const WMEvent event(desired_snap_state == WindowStateType::kLeftSnapped
-                              ? WM_EVENT_SNAP_LEFT
-                              : WM_EVENT_SNAP_RIGHT);
+      const WMEvent event(desired_snap_state == WindowStateType::kPrimarySnapped
+                              ? WM_EVENT_SNAP_PRIMARY
+                              : WM_EVENT_SNAP_SECONDARY);
       window_state->OnWMEvent(&event);
     }
     return;
@@ -210,12 +210,12 @@
   if (ShouldAllowSplitView()) {
     bounds_in_parent =
         SplitViewController::Get(window)->GetSnappedWindowBoundsInParent(
-            (state_type == WindowStateType::kLeftSnapped)
+            (state_type == WindowStateType::kPrimarySnapped)
                 ? SplitViewController::LEFT
                 : SplitViewController::RIGHT,
             window);
   } else {
-    bounds_in_parent = (state_type == WindowStateType::kLeftSnapped)
+    bounds_in_parent = (state_type == WindowStateType::kPrimarySnapped)
                            ? GetDefaultLeftSnappedWindowBoundsInParent(window)
                            : GetDefaultRightSnappedWindowBoundsInParent(window);
   }
@@ -224,7 +224,8 @@
 
 void BaseState::HandleWindowSnapping(WindowState* window_state,
                                      WMEventType event_type) {
-  DCHECK(event_type == WM_EVENT_SNAP_LEFT || event_type == WM_EVENT_SNAP_RIGHT);
+  DCHECK(event_type == WM_EVENT_SNAP_PRIMARY ||
+         event_type == WM_EVENT_SNAP_SECONDARY);
   DCHECK(window_state->CanSnap());
 
   window_state->set_bounds_changed_by_user(true);
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc
index 9f2139b..ded09d7 100644
--- a/ash/wm/client_controlled_state.cc
+++ b/ash/wm/client_controlled_state.cc
@@ -108,15 +108,15 @@
       delegate_->HandleWindowStateRequest(window_state, next_state);
       break;
     }
-    case WM_EVENT_SNAP_LEFT:
-    case WM_EVENT_SNAP_RIGHT: {
+    case WM_EVENT_SNAP_PRIMARY:
+    case WM_EVENT_SNAP_SECONDARY: {
       if (window_state->CanSnap()) {
         HandleWindowSnapping(window_state, event->type());
         // Get the desired window bounds for the snap state.
         gfx::Rect bounds = GetSnappedWindowBoundsInParent(
-            window, event->type() == WM_EVENT_SNAP_LEFT
-                        ? WindowStateType::kLeftSnapped
-                        : WindowStateType::kRightSnapped);
+            window, event->type() == WM_EVENT_SNAP_PRIMARY
+                        ? WindowStateType::kPrimarySnapped
+                        : WindowStateType::kSecondarySnapped);
 
         // We don't want Unminimize() to restore the pre-snapped state during
         // the transition.
@@ -213,8 +213,8 @@
     case WM_EVENT_TOGGLE_FULLSCREEN:
       ToggleFullScreen(window_state, window_state->delegate());
       break;
-    case WM_EVENT_CYCLE_SNAP_LEFT:
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
+    case WM_EVENT_CYCLE_SNAP_PRIMARY:
+    case WM_EVENT_CYCLE_SNAP_SECONDARY:
       CycleSnap(window_state, event->type());
       break;
     default:
diff --git a/ash/wm/client_controlled_state_unittest.cc b/ash/wm/client_controlled_state_unittest.cc
index bd0cb44..1e70d6f 100644
--- a/ash/wm/client_controlled_state_unittest.cc
+++ b/ash/wm/client_controlled_state_unittest.cc
@@ -48,8 +48,8 @@
                            int64_t display_id) override {
     requested_bounds_ = bounds;
     if (requested_state != window_state->GetStateType()) {
-      DCHECK(requested_state == WindowStateType::kLeftSnapped ||
-             requested_state == WindowStateType::kRightSnapped);
+      DCHECK(requested_state == WindowStateType::kPrimarySnapped ||
+             requested_state == WindowStateType::kSecondarySnapped);
       old_state_ = window_state->GetStateType();
       new_state_ = requested_state;
     }
@@ -333,12 +333,12 @@
   ASSERT_FALSE(window_state()->CanSnap());
 
   // The event should be ignored.
-  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap_left_event);
   EXPECT_FALSE(window_state()->IsSnapped());
   EXPECT_TRUE(delegate()->requested_bounds().IsEmpty());
 
-  const WMEvent snap_right_event(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent snap_right_event(WM_EVENT_CYCLE_SNAP_SECONDARY);
   window_state()->OnWMEvent(&snap_right_event);
   EXPECT_FALSE(window_state()->IsSnapped());
   EXPECT_TRUE(delegate()->requested_bounds().IsEmpty());
@@ -354,7 +354,7 @@
   EXPECT_EQ(work_area.height(), delegate()->requested_bounds().height());
   EXPECT_TRUE(delegate()->requested_bounds().origin().IsOrigin());
   EXPECT_EQ(WindowStateType::kDefault, delegate()->old_state());
-  EXPECT_EQ(WindowStateType::kLeftSnapped, delegate()->new_state());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, delegate()->new_state());
 
   delegate()->Reset();
 
@@ -365,7 +365,7 @@
   EXPECT_EQ(work_area.bottom_right(),
             delegate()->requested_bounds().bottom_right());
   EXPECT_EQ(WindowStateType::kDefault, delegate()->old_state());
-  EXPECT_EQ(WindowStateType::kRightSnapped, delegate()->new_state());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, delegate()->new_state());
 }
 
 TEST_F(ClientControlledStateTest, SnapInSecondaryDisplay) {
@@ -380,7 +380,7 @@
   widget_delegate()->EnableSnap();
 
   // Make sure the requested bounds for snapped window is local to display.
-  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap_left_event);
 
   EXPECT_EQ(second_display_id, delegate()->display_id());
@@ -600,13 +600,13 @@
   split_view_controller->SnapWindow(window_state()->window(),
                                     SplitViewController::SnapPosition::RIGHT);
 
-  EXPECT_EQ(WindowStateType::kRightSnapped, delegate()->new_state());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, delegate()->new_state());
   EXPECT_FALSE(window_state()->IsSnapped());
 
   // Ensures the window is in a transitional snapped state.
   EXPECT_TRUE(split_view_controller->IsWindowInTransitionalState(
       window_state()->window()));
-  EXPECT_EQ(WindowStateType::kRightSnapped, delegate()->new_state());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, delegate()->new_state());
   EXPECT_FALSE(window_state()->IsSnapped());
 
   // Ignores WMEvent if in a transitional state.
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index fcaeae3..7805f149 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -299,8 +299,8 @@
     case WM_EVENT_TOGGLE_FULLSCREEN:
       ToggleFullScreen(window_state, window_state->delegate());
       return;
-    case WM_EVENT_CYCLE_SNAP_LEFT:
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
+    case WM_EVENT_CYCLE_SNAP_PRIMARY:
+    case WM_EVENT_CYCLE_SNAP_SECONDARY:
       CycleSnap(window_state, event->type());
       return;
     default:
@@ -343,14 +343,14 @@
   }
 
   const WMEventType type = event->type();
-  if (type == WM_EVENT_SNAP_LEFT || type == WM_EVENT_SNAP_RIGHT)
+  if (type == WM_EVENT_SNAP_PRIMARY || type == WM_EVENT_SNAP_SECONDARY)
     HandleWindowSnapping(window_state, type);
 
   if (next_state_type == current_state_type && window_state->IsSnapped()) {
     gfx::Rect snapped_bounds = GetSnappedWindowBoundsInParent(
-        window_state->window(), event->type() == WM_EVENT_SNAP_LEFT
-                                    ? WindowStateType::kLeftSnapped
-                                    : WindowStateType::kRightSnapped);
+        window_state->window(), event->type() == WM_EVENT_SNAP_PRIMARY
+                                    ? WindowStateType::kPrimarySnapped
+                                    : WindowStateType::kSecondarySnapped);
     window_state->SetBoundsDirectAnimated(snapped_bounds);
     return;
   }
@@ -506,8 +506,8 @@
   aura::Window* window = window_state->window();
   gfx::Rect bounds_in_parent;
   switch (state_type_) {
-    case WindowStateType::kLeftSnapped:
-    case WindowStateType::kRightSnapped:
+    case WindowStateType::kPrimarySnapped:
+    case WindowStateType::kSecondarySnapped:
       bounds_in_parent =
           GetSnappedWindowBoundsInParent(window_state->window(), state_type_);
       break;
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index be15f46..e7d7877d 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -2943,9 +2943,9 @@
   auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
   WindowState* win0_state = WindowState::Get(win0.get());
-  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_LEFT);
+  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   win0_state->OnWMEvent(&snap_to_left);
-  EXPECT_EQ(chromeos::WindowStateType::kLeftSnapped,
+  EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
             win0_state->GetStateType());
 
   // Switch to |desk_2| and then back to |desk_1|. Verify that neither split
diff --git a/ash/wm/full_restore/full_restore_controller.cc b/ash/wm/full_restore/full_restore_controller.cc
index 0688277..deef155 100644
--- a/ash/wm/full_restore/full_restore_controller.cc
+++ b/ash/wm/full_restore/full_restore_controller.cc
@@ -503,14 +503,14 @@
       if (Shell::Get()->tablet_mode_controller()->InTabletMode())
         Shell::Get()->tablet_mode_controller()->AddWindow(window);
 
-      if (*state_type == chromeos::WindowStateType::kLeftSnapped ||
-          *state_type == chromeos::WindowStateType::kRightSnapped) {
+      if (*state_type == chromeos::WindowStateType::kPrimarySnapped ||
+          *state_type == chromeos::WindowStateType::kSecondarySnapped) {
         base::AutoReset<bool> auto_reset_is_restoring_snap_state(
             &is_restoring_snap_state_, true);
-        const WMEvent snap_event(*state_type ==
-                                         chromeos::WindowStateType::kLeftSnapped
-                                     ? WM_EVENT_SNAP_LEFT
-                                     : WM_EVENT_SNAP_RIGHT);
+        const WMEvent snap_event(
+            *state_type == chromeos::WindowStateType::kPrimarySnapped
+                ? WM_EVENT_SNAP_PRIMARY
+                : WM_EVENT_SNAP_SECONDARY);
         WindowState::Get(window)->OnWMEvent(&snap_event);
       }
     }
diff --git a/ash/wm/full_restore/full_restore_controller_unittest.cc b/ash/wm/full_restore/full_restore_controller_unittest.cc
index 2500da68..f223ee27 100644
--- a/ash/wm/full_restore/full_restore_controller_unittest.cc
+++ b/ash/wm/full_restore/full_restore_controller_unittest.cc
@@ -649,9 +649,9 @@
   // other snapped right.
   const gfx::Rect restored_bounds(200, 200);
   AddEntryToFakeFile(/*restore_window_id=*/2, restored_bounds,
-                     chromeos::WindowStateType::kLeftSnapped);
+                     chromeos::WindowStateType::kPrimarySnapped);
   AddEntryToFakeFile(/*restore_window_id=*/3, restored_bounds,
-                     chromeos::WindowStateType::kRightSnapped);
+                     chromeos::WindowStateType::kSecondarySnapped);
 
   // Create two full restore windows with the same restore window ids as the
   // entries we added. Test they are snapped and have snapped bounds.
@@ -773,9 +773,9 @@
   ASSERT_TRUE(window1_info->window_state_type);
   ASSERT_TRUE(window2_info->window_state_type);
 
-  EXPECT_EQ(chromeos::WindowStateType::kLeftSnapped,
+  EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
             *window1_info->window_state_type);
-  EXPECT_EQ(chromeos::WindowStateType::kRightSnapped,
+  EXPECT_EQ(chromeos::WindowStateType::kSecondarySnapped,
             *window2_info->window_state_type);
   EXPECT_EQ(bounds, *window1_info->current_bounds);
   EXPECT_EQ(bounds, *window2_info->current_bounds);
@@ -788,9 +788,9 @@
   // other snapped right.
   const gfx::Rect restored_bounds(200, 200);
   AddEntryToFakeFile(/*restore_window_id=*/2, restored_bounds,
-                     chromeos::WindowStateType::kLeftSnapped);
+                     chromeos::WindowStateType::kPrimarySnapped);
   AddEntryToFakeFile(/*restore_window_id=*/3, restored_bounds,
-                     chromeos::WindowStateType::kRightSnapped);
+                     chromeos::WindowStateType::kSecondarySnapped);
 
   TabletModeControllerTestApi().EnterTabletMode();
 
@@ -1118,7 +1118,7 @@
                      chromeos::WindowStateType::kNormal, /*activation_index=*/2,
                      /*display_id=*/primary_id);
   AddEntryToFakeFile(/*restore_id=*/3, kFullBounds,
-                     chromeos::WindowStateType::kLeftSnapped,
+                     chromeos::WindowStateType::kPrimarySnapped,
                      /*activation_index=*/3, /*display_id=*/primary_id);
 
   // Restore the first window. The window should have the exact same bounds.
diff --git a/ash/wm/lock_window_state.cc b/ash/wm/lock_window_state.cc
index b69fead..b4d60c2 100644
--- a/ash/wm/lock_window_state.cc
+++ b/ash/wm/lock_window_state.cc
@@ -51,11 +51,11 @@
     case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
     case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
     case WM_EVENT_TOGGLE_MAXIMIZE:
-    case WM_EVENT_CYCLE_SNAP_LEFT:
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
+    case WM_EVENT_CYCLE_SNAP_PRIMARY:
+    case WM_EVENT_CYCLE_SNAP_SECONDARY:
     case WM_EVENT_CENTER:
-    case WM_EVENT_SNAP_LEFT:
-    case WM_EVENT_SNAP_RIGHT:
+    case WM_EVENT_SNAP_PRIMARY:
+    case WM_EVENT_SNAP_SECONDARY:
     case WM_EVENT_NORMAL:
     case WM_EVENT_MAXIMIZE:
       UpdateWindow(window_state,
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 6fa4ff6..0a41afc 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -4770,10 +4770,10 @@
   EXPECT_EQ(SplitViewController::State::kNoSnap,
             split_view_controller()->state());
   EXPECT_FALSE(InOverviewSession());
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   snapped_window_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
-  EXPECT_EQ(WindowStateType::kLeftSnapped,
+  EXPECT_EQ(WindowStateType::kPrimarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_EQ(SplitViewController::State::kLeftSnapped,
             split_view_controller()->state());
@@ -4791,10 +4791,10 @@
   EXPECT_EQ(SplitViewController::State::kNoSnap,
             split_view_controller()->state());
   EXPECT_FALSE(InOverviewSession());
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
   snapped_window_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
-  EXPECT_EQ(WindowStateType::kRightSnapped,
+  EXPECT_EQ(WindowStateType::kSecondarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_EQ(SplitViewController::State::kRightSnapped,
             split_view_controller()->state());
@@ -4818,10 +4818,10 @@
         EXPECT_FALSE(InOverviewSession());
       };
   expect_unsnappable_window_is_active_and_maximized();
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   unsnappable_window_state->OnWMEvent(&alt_left_square_bracket);
   expect_unsnappable_window_is_active_and_maximized();
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
   unsnappable_window_state->OnWMEvent(&alt_right_square_bracket);
   expect_unsnappable_window_is_active_and_maximized();
 }
@@ -4845,36 +4845,36 @@
   // Test Alt+[ with active window snapped on left and overview on right.
   ToggleOverview();
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
-  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_LEFT);
+  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_PRIMARY);
   // Test Alt+] with active window snapped on right and overview on left.
   ToggleOverview();
   split_view_controller()->SnapWindow(window1.get(),
                                       SplitViewController::RIGHT);
-  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_RIGHT);
+  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_SECONDARY);
   // Test Alt+[ with active window snapped on left and other window snapped on
   // right, if the left window is the default snapped window.
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_LEFT);
+  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_PRIMARY);
   // Test Alt+[ with active window snapped on left and other window snapped on
   // right, if the right window is the default snapped window.
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
-  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_LEFT);
+  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_PRIMARY);
   // Test Alt+] with active window snapped on right and other window snapped on
   // left, if the left window is the default snapped window.
   split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window1.get(),
                                       SplitViewController::RIGHT);
-  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_RIGHT);
+  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_SECONDARY);
   // Test Alt+] with active window snapped on right and other window snapped on
   // left, if the right window is the default snapped window.
   split_view_controller()->SnapWindow(window1.get(),
                                       SplitViewController::RIGHT);
   split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
-  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_RIGHT);
+  test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_SECONDARY);
 }
 
 // Tests using Alt+[ on a right snapped window, and Alt+] on a left snapped
@@ -4886,10 +4886,10 @@
   const auto test_left_snapping_window1 = [this, &window1, &window2]() {
     wm::ActivateWindow(window1.get());
     WindowState* window1_state = WindowState::Get(window1.get());
-    const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
+    const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
     window1_state->OnWMEvent(&alt_left_square_bracket);
     EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
-    EXPECT_EQ(WindowStateType::kLeftSnapped, window1_state->GetStateType());
+    EXPECT_EQ(WindowStateType::kPrimarySnapped, window1_state->GetStateType());
     EXPECT_EQ(SplitViewController::State::kLeftSnapped,
               split_view_controller()->state());
     EXPECT_EQ(window1.get(), split_view_controller()->left_window());
@@ -4899,10 +4899,11 @@
   const auto test_right_snapping_window1 = [this, &window1, &window2]() {
     wm::ActivateWindow(window1.get());
     WindowState* window1_state = WindowState::Get(window1.get());
-    const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
+    const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
     window1_state->OnWMEvent(&alt_right_square_bracket);
     EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
-    EXPECT_EQ(WindowStateType::kRightSnapped, window1_state->GetStateType());
+    EXPECT_EQ(WindowStateType::kSecondarySnapped,
+              window1_state->GetStateType());
     EXPECT_EQ(SplitViewController::State::kRightSnapped,
               split_view_controller()->state());
     EXPECT_EQ(window1.get(), split_view_controller()->right_window());
@@ -6204,7 +6205,7 @@
   DragWindowTo(overview_item1, gfx::PointF(0, 0));
   // Since the only window is snapped, overview and splitview should be both
   // ended.
-  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
+  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kPrimarySnapped);
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 
@@ -6223,7 +6224,7 @@
   EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window1.get()));
   EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview(
       window2.get()));
-  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kRightSnapped);
+  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kSecondarySnapped);
   // Close |window2| will end overview and splitview.
   window2.reset();
   EXPECT_FALSE(overview_controller()->InOverviewSession());
@@ -6236,9 +6237,9 @@
   DragWindowTo(overview_item1, gfx::PointF(0, 0));
   OverviewItem* overview_item3 = GetOverviewItemForWindow(window3.get());
   DragWindowTo(overview_item3, gfx::PointF(600, 300));
-  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
+  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kPrimarySnapped);
   EXPECT_EQ(WindowState::Get(window3.get())->GetStateType(),
-            WindowStateType::kRightSnapped);
+            WindowStateType::kSecondarySnapped);
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 
@@ -6257,9 +6258,9 @@
       window3.get()));
   EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview(
       window1.get()));
-  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
+  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kPrimarySnapped);
   EXPECT_EQ(WindowState::Get(window3.get())->GetStateType(),
-            WindowStateType::kLeftSnapped);
+            WindowStateType::kPrimarySnapped);
   EXPECT_TRUE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   // End overview, test that we'll not auto-snap a window to the right side of
@@ -6890,16 +6891,16 @@
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(InOverviewSession());
   // Alt+[
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   WindowState* window1_state = WindowState::Get(window1.get());
   window1_state->OnWMEvent(&alt_left_square_bracket);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window1_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window1_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(InOverviewSession());
   // Alt+]
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
   window1_state->OnWMEvent(&alt_right_square_bracket);
-  EXPECT_EQ(WindowStateType::kRightSnapped, window1_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, window1_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(InOverviewSession());
 }
@@ -6913,11 +6914,11 @@
   split_view_controller()->SnapWindow(snapped_window.get(),
                                       SplitViewController::LEFT);
   WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
-  EXPECT_EQ(WindowStateType::kLeftSnapped,
+  EXPECT_EQ(WindowStateType::kPrimarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(InOverviewSession());
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   snapped_window_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_EQ(WindowStateType::kNormal, snapped_window_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
@@ -6933,11 +6934,11 @@
   split_view_controller()->SnapWindow(snapped_window.get(),
                                       SplitViewController::RIGHT);
   WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
-  EXPECT_EQ(WindowStateType::kRightSnapped,
+  EXPECT_EQ(WindowStateType::kSecondarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(InOverviewSession());
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
   snapped_window_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_EQ(WindowStateType::kNormal, snapped_window_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
@@ -6956,27 +6957,27 @@
                                       SplitViewController::RIGHT);
   wm::ActivateWindow(snapped_window.get());
   WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
-  EXPECT_EQ(WindowStateType::kRightSnapped,
+  EXPECT_EQ(WindowStateType::kSecondarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_EQ(SplitViewController::State::kRightSnapped,
             split_view_controller()->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller()->right_window());
   EXPECT_TRUE(InOverviewSession());
   // Test using Alt+[ to put |snapped_window| on the left.
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   snapped_window_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
-  EXPECT_EQ(WindowStateType::kLeftSnapped,
+  EXPECT_EQ(WindowStateType::kPrimarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_EQ(SplitViewController::State::kLeftSnapped,
             split_view_controller()->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller()->left_window());
   EXPECT_TRUE(InOverviewSession());
   // Test using Alt+] to put |snapped_window| on the right.
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
   snapped_window_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
-  EXPECT_EQ(WindowStateType::kRightSnapped,
+  EXPECT_EQ(WindowStateType::kSecondarySnapped,
             snapped_window_state->GetStateType());
   EXPECT_EQ(SplitViewController::State::kRightSnapped,
             split_view_controller()->state());
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 1019b9f..601ef3c 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -149,9 +149,9 @@
     SplitViewController::SnapPosition snap_position) {
   DCHECK(snap_position != SplitViewController::NONE);
   if (snap_position == SplitViewController::LEFT)
-    return WindowStateType::kLeftSnapped;
+    return WindowStateType::kPrimarySnapped;
   if (snap_position == SplitViewController::RIGHT)
-    return WindowStateType::kRightSnapped;
+    return WindowStateType::kSecondarySnapped;
   NOTREACHED();
   return WindowStateType::kDefault;
 }
@@ -777,8 +777,8 @@
                                          .id());
   }
 
-  const WMEvent event(snap_position == LEFT ? WM_EVENT_SNAP_LEFT
-                                            : WM_EVENT_SNAP_RIGHT);
+  const WMEvent event(snap_position == LEFT ? WM_EVENT_SNAP_PRIMARY
+                                            : WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window)->OnWMEvent(&event);
 
   base::RecordAction(base::UserMetricsAction("SplitView_SnapWindow"));
@@ -786,7 +786,8 @@
 
 void SplitViewController::OnWindowSnapWMEvent(aura::Window* window,
                                               WMEventType event_type) {
-  DCHECK(event_type == WM_EVENT_SNAP_LEFT || event_type == WM_EVENT_SNAP_RIGHT);
+  DCHECK(event_type == WM_EVENT_SNAP_PRIMARY ||
+         event_type == WM_EVENT_SNAP_SECONDARY);
 
   // If split view can't be enabled at the moment, do nothing.
   if (!ShouldAllowSplitView())
@@ -806,7 +807,7 @@
 
   // Start observe the to-be-snapped window.
   to_be_snapped_windows_observer_->AddToBeSnappedWindow(
-      window, event_type == WM_EVENT_SNAP_LEFT ? LEFT : RIGHT);
+      window, event_type == WM_EVENT_SNAP_PRIMARY ? LEFT : RIGHT);
 }
 
 void SplitViewController::AttachSnappingWindow(aura::Window* window,
@@ -1811,11 +1812,11 @@
 void SplitViewController::UpdateSnappedWindowsAndDividerBounds() {
   // Update the snapped windows' bounds.
   if (IsSnapped(left_window_)) {
-    const WMEvent left_window_event(WM_EVENT_SNAP_LEFT);
+    const WMEvent left_window_event(WM_EVENT_SNAP_PRIMARY);
     WindowState::Get(left_window_)->OnWMEvent(&left_window_event);
   }
   if (IsSnapped(right_window_)) {
-    const WMEvent right_window_event(WM_EVENT_SNAP_RIGHT);
+    const WMEvent right_window_event(WM_EVENT_SNAP_SECONDARY);
     WindowState::Get(right_window_)->OnWMEvent(&right_window_event);
   }
 
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 5674006..a0459b9 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -153,8 +153,8 @@
                   bool activate_window = false);
 
   // This is called by WindowState::State when receiving a snap WMEvent (i.e.,
-  // WM_EVENT_SNAP_LEFT or WM_EVENT_SNAP_RIGHT). SplitViewController will decide
-  // if this window needs to be snapped in split view.
+  // WM_EVENT_SNAP_PRIMARY or WM_EVENT_SNAP_SECONDARY). SplitViewController will
+  // decide if this window needs to be snapped in split view.
   void OnWindowSnapWMEvent(aura::Window* window, WMEventType event_type);
 
   // Attaches the to-be-snapped |window| to split view at |snap_position|. It
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 378c428d..cd6ce4bb 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -2854,8 +2854,8 @@
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 
   // Test the functionalities in tablet mode.
-  // Sending WM_EVENT_SNAP_RIGHT to |window1| will snap to left.
-  WMEvent wm_left_snap_event(WM_EVENT_SNAP_LEFT);
+  // Sending WM_EVENT_SNAP_SECONDARY to |window1| will snap to left.
+  WMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window1.get())->OnWMEvent(&wm_left_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
@@ -2865,8 +2865,8 @@
   OverviewSession* overview_session = overview_controller->overview_session();
   EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get()));
 
-  // Sending WM_EVENT_SNAP_RIGHT to |window1| will snap to right.
-  WMEvent wm_right_snap_event(WM_EVENT_SNAP_RIGHT);
+  // Sending WM_EVENT_SNAP_SECONDARY to |window1| will snap to right.
+  WMEvent wm_right_snap_event(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window1.get())->OnWMEvent(&wm_right_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
@@ -2874,7 +2874,7 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get()));
 
-  // Sending WM_EVENT_SNAP_RIGHT to |window2| will replace |window1|.
+  // Sending WM_EVENT_SNAP_SECONDARY to |window2| will replace |window1|.
   WindowState::Get(window2.get())->OnWMEvent(&wm_right_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
@@ -2882,14 +2882,14 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get()));
 
-  // Sending WM_EVENT_SNAP_LEFT to |window1| to snap |window1|.
+  // Sending WM_EVENT_SNAP_PRIMARY to |window1| to snap |window1|.
   WindowState::Get(window1.get())->OnWMEvent(&wm_left_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
   EXPECT_FALSE(overview_controller->InOverviewSession());
 
-  // Sending WM_EVENT_SNAP_RIGHT to |window1| will replace |window2| and put
+  // Sending WM_EVENT_SNAP_SECONDARY to |window1| will replace |window2| and put
   // |window2| in overview.
   WindowState::Get(window1.get())->OnWMEvent(&wm_right_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
@@ -2903,23 +2903,23 @@
 
   // Test the functionalities in clamshell mode.
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
-  // Sending WM_EVENT_SNAP_LEFT to |window1| will snap to left but won't put
+  // Sending WM_EVENT_SNAP_PRIMARY to |window1| will snap to left but won't put
   // |window1| in splitview.
   WindowState::Get(window1.get())->OnWMEvent(&wm_left_snap_event);
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(overview_controller->InOverviewSession());
 
   ToggleOverview();
-  // Sending WM_EVENT_SNAP_LEFT to |window1| to snap to left while overview is
-  // active will put |window1| in splitview and |window2| in overview.
+  // Sending WM_EVENT_SNAP_PRIMARY to |window1| to snap to left while overview
+  // is active will put |window1| in splitview and |window2| in overview.
   WindowState::Get(window1.get())->OnWMEvent(&wm_left_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(overview_controller->InOverviewSession());
   overview_session = overview_controller->overview_session();
   EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get()));
 
-  // Sending WM_EVENT_SNAP_RIGHT to |window1| to snap to right while overview
-  // is active will put |window1| to snap to the right in splitview and
+  // Sending WM_EVENT_SNAP_SECONDARY to |window1| to snap to right while
+  // overview is active will put |window1| to snap to the right in splitview and
   // |window2| remains in overview.
   WindowState::Get(window1.get())->OnWMEvent(&wm_right_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
@@ -4750,7 +4750,7 @@
   // Switch to clamshell mode and check that |snapped_window| keeps its snapped
   // window state.
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
-  EXPECT_EQ(chromeos::WindowStateType::kLeftSnapped,
+  EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
             WindowState::Get(snapped_window.get())->GetStateType());
 }
 
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index 3e01853..3c7ce9163 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -356,14 +356,14 @@
       }
 
       switch (WindowState::Get(window)->GetStateType()) {
-        case WindowStateType::kLeftSnapped:
+        case WindowStateType::kPrimarySnapped:
           if (!split_view_controller->left_window()) {
             split_view_controller->SnapWindow(window,
                                               SplitViewController::LEFT);
           }
           break;
 
-        case WindowStateType::kRightSnapped:
+        case WindowStateType::kSecondarySnapped:
           if (!split_view_controller->right_window()) {
             split_view_controller->SnapWindow(window,
                                               SplitViewController::RIGHT);
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index ff6989b..1f1522a 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -203,7 +203,7 @@
   std::unique_ptr<aura::Window> CreateDesktopWindowSnappedLeft(
       const gfx::Rect& bounds = gfx::Rect()) {
     std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
-    WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_LEFT);
+    WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
     WindowState::Get(window.get())->OnWMEvent(&snap_to_left);
     return window;
   }
@@ -212,7 +212,7 @@
   std::unique_ptr<aura::Window> CreateDesktopWindowSnappedRight(
       const gfx::Rect& bounds = gfx::Rect()) {
     std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
-    WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_RIGHT);
+    WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
     WindowState::Get(window.get())->OnWMEvent(&snap_to_right);
     return window;
   }
@@ -1351,7 +1351,7 @@
   WindowState* left_window_state = WindowState::Get(left_window.get());
   ASSERT_TRUE(left_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(left_window.get()));
-  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_LEFT);
+  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   left_window_state->OnWMEvent(&snap_to_left);
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
@@ -1381,7 +1381,7 @@
   WindowState* right_window_state = WindowState::Get(right_window.get());
   ASSERT_TRUE(right_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(right_window.get()));
-  WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_RIGHT);
+  WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
   right_window_state->OnWMEvent(&snap_to_right);
   wm::ActivateWindow(right_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
@@ -1410,7 +1410,7 @@
   WindowState* right_window_state = WindowState::Get(right_window.get());
   ASSERT_TRUE(right_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(right_window.get()));
-  WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_RIGHT);
+  WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
   right_window_state->OnWMEvent(&snap_to_right);
   ASSERT_EQ(left_window.get(), window_util::GetActiveWindow());
   tablet_mode_controller()->SetEnabledForTest(true);
@@ -1438,7 +1438,7 @@
   WindowState* left_window_state = WindowState::Get(left_window.get());
   ASSERT_TRUE(left_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(left_window.get()));
-  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_LEFT);
+  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   left_window_state->OnWMEvent(&snap_to_left);
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index bd35a92..c21853e 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -73,7 +73,7 @@
 
   for (auto& iter : windows) {
     split_view_controller->SnapWindow(
-        iter.first, iter.second == WindowStateType::kLeftSnapped
+        iter.first, iter.second == WindowStateType::kPrimarySnapped
                         ? SplitViewController::LEFT
                         : SplitViewController::RIGHT);
   }
@@ -505,24 +505,24 @@
   aura::Window* root_window = Shell::GetPrimaryRootWindow();
   if (IsCarryOverCandidateForSplitView(mru_windows, 0u, root_window)) {
     if (GetWindowStateType(mru_windows[0], clamshell_to_tablet) ==
-        WindowStateType::kLeftSnapped) {
+        WindowStateType::kPrimarySnapped) {
       windows.emplace_back(
-          std::make_pair(mru_windows[0], WindowStateType::kLeftSnapped));
+          std::make_pair(mru_windows[0], WindowStateType::kPrimarySnapped));
       if (IsCarryOverCandidateForSplitView(mru_windows, 1u, root_window) &&
           GetWindowStateType(mru_windows[1], clamshell_to_tablet) ==
-              WindowStateType::kRightSnapped) {
+              WindowStateType::kSecondarySnapped) {
         windows.emplace_back(
-            std::make_pair(mru_windows[1], WindowStateType::kRightSnapped));
+            std::make_pair(mru_windows[1], WindowStateType::kSecondarySnapped));
       }
     } else if (GetWindowStateType(mru_windows[0], clamshell_to_tablet) ==
-               WindowStateType::kRightSnapped) {
+               WindowStateType::kSecondarySnapped) {
       windows.emplace_back(
-          std::make_pair(mru_windows[0], WindowStateType::kRightSnapped));
+          std::make_pair(mru_windows[0], WindowStateType::kSecondarySnapped));
       if (IsCarryOverCandidateForSplitView(mru_windows, 1u, root_window) &&
           GetWindowStateType(mru_windows[1], clamshell_to_tablet) ==
-              WindowStateType::kLeftSnapped) {
+              WindowStateType::kPrimarySnapped) {
         windows.emplace_back(
-            std::make_pair(mru_windows[1], WindowStateType::kLeftSnapped));
+            std::make_pair(mru_windows[1], WindowStateType::kPrimarySnapped));
       }
     }
   }
@@ -535,9 +535,9 @@
   aura::Window* left_window = nullptr;
   aura::Window* right_window = nullptr;
   for (auto& iter : windows_in_splitview) {
-    if (iter.second == WindowStateType::kLeftSnapped)
+    if (iter.second == WindowStateType::kPrimarySnapped)
       left_window = iter.first;
-    else if (iter.second == WindowStateType::kRightSnapped)
+    else if (iter.second == WindowStateType::kSecondarySnapped)
       right_window = iter.first;
   }
   if (!left_window && !right_window)
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index a43d2d8..6d9db1bf 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -1651,7 +1651,7 @@
 
   // 5. Clamshell -> Tablet. If the window is snapped, it will be carried over
   // to splitview in tablet mode.
-  const WMEvent event(WM_EVENT_SNAP_LEFT);
+  const WMEvent event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window.get())->OnWMEvent(&event);
   EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped());
   // After transition, we should be in single split screen.
@@ -1723,7 +1723,7 @@
   OverviewController* overview_controller = Shell::Get()->overview_controller();
 
   // First test 1 window case.
-  const WMEvent left_snap_event(WM_EVENT_SNAP_LEFT);
+  const WMEvent left_snap_event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window.get())->OnWMEvent(&left_snap_event);
   const gfx::Rect left_snapped_bounds =
       gfx::Rect(1200 / 2, 800 - ShelfConfig::Get()->shelf_size());
@@ -1746,7 +1746,7 @@
   std::unique_ptr<aura::Window> window2(
       CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
   WindowState::Get(window.get())->OnWMEvent(&left_snap_event);
-  const WMEvent right_snap_event(WM_EVENT_SNAP_RIGHT);
+  const WMEvent right_snap_event(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window2.get())->OnWMEvent(&right_snap_event);
   // Change their bounds horizontally and then enter tablet mode.
   window->SetBounds(gfx::Rect(400, left_snapped_bounds.height()));
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.cc b/ash/wm/tablet_mode/tablet_mode_window_state.cc
index 0f6dcf4..097a116 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.cc
@@ -88,12 +88,12 @@
   if (state_object->IsFullscreen() || state_object->IsPinned())
     return screen_util::GetFullscreenWindowBoundsInParent(window);
 
-  if (state_object->GetStateType() == WindowStateType::kLeftSnapped) {
+  if (state_object->GetStateType() == WindowStateType::kPrimarySnapped) {
     return SplitViewController::Get(Shell::GetPrimaryRootWindow())
         ->GetSnappedWindowBoundsInParent(SplitViewController::LEFT, window);
   }
 
-  if (state_object->GetStateType() == WindowStateType::kRightSnapped) {
+  if (state_object->GetStateType() == WindowStateType::kSecondarySnapped) {
     return SplitViewController::Get(Shell::GetPrimaryRootWindow())
         ->GetSnappedWindowBoundsInParent(SplitViewController::RIGHT, window);
   }
@@ -162,8 +162,8 @@
 }
 
 bool IsSnapped(WindowStateType state) {
-  return state == WindowStateType::kLeftSnapped ||
-         state == WindowStateType::kRightSnapped;
+  return state == WindowStateType::kPrimarySnapped ||
+         state == WindowStateType::kSecondarySnapped;
 }
 
 // Returns true if the bounds change of |window| is from VK request and can be
@@ -282,14 +282,14 @@
       UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state),
                    true /* animated */);
       return;
-    case WM_EVENT_SNAP_LEFT:
-    case WM_EVENT_SNAP_RIGHT:
+    case WM_EVENT_SNAP_PRIMARY:
+    case WM_EVENT_SNAP_SECONDARY:
       DoTabletSnap(window_state, event->type());
       return;
-    case WM_EVENT_CYCLE_SNAP_LEFT:
+    case WM_EVENT_CYCLE_SNAP_PRIMARY:
       CycleTabletSnap(window_state, SplitViewController::LEFT);
       return;
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
+    case WM_EVENT_CYCLE_SNAP_SECONDARY:
       CycleTabletSnap(window_state, SplitViewController::RIGHT);
       return;
     case WM_EVENT_MINIMIZE:
@@ -322,8 +322,8 @@
                  current_state_type_ != WindowStateType::kFullscreen &&
                  current_state_type_ != WindowStateType::kPinned &&
                  current_state_type_ != WindowStateType::kTrustedPinned &&
-                 current_state_type_ != WindowStateType::kLeftSnapped &&
-                 current_state_type_ != WindowStateType::kRightSnapped) {
+                 current_state_type_ != WindowStateType::kPrimarySnapped &&
+                 current_state_type_ != WindowStateType::kSecondarySnapped) {
         // In all other cases (except for minimized windows) we respect the
         // requested bounds and center it to a fully visible area on the screen.
         bounds_in_parent = GetCenteredBounds(bounds_in_parent, window_state);
@@ -406,8 +406,8 @@
           (!window_state->CanMaximize() ||
            !!::wm::GetTransientParent(window_state->window()))) ||
          target_state == WindowStateType::kFullscreen ||
-         target_state == WindowStateType::kLeftSnapped ||
-         target_state == WindowStateType::kRightSnapped);
+         target_state == WindowStateType::kPrimarySnapped ||
+         target_state == WindowStateType::kSecondarySnapped);
 
   if (current_state_type_ == target_state) {
     if (target_state == WindowStateType::kMinimized)
@@ -462,8 +462,8 @@
 WindowStateType TabletModeWindowState::GetSnappedWindowStateType(
     WindowState* window_state,
     WindowStateType target_state) {
-  DCHECK(target_state == WindowStateType::kLeftSnapped ||
-         target_state == WindowStateType::kRightSnapped);
+  DCHECK(target_state == WindowStateType::kPrimarySnapped ||
+         target_state == WindowStateType::kSecondarySnapped);
   return SplitViewController::Get(Shell::GetPrimaryRootWindow())
                  ->CanSnapWindow(window_state->window())
              ? target_state
@@ -531,8 +531,8 @@
 
 void TabletModeWindowState::DoTabletSnap(WindowState* window_state,
                                          WMEventType snap_event_type) {
-  DCHECK(snap_event_type == WM_EVENT_SNAP_LEFT ||
-         snap_event_type == WM_EVENT_SNAP_RIGHT);
+  DCHECK(snap_event_type == WM_EVENT_SNAP_PRIMARY ||
+         snap_event_type == WM_EVENT_SNAP_SECONDARY);
 
   aura::Window* window = window_state->window();
   SplitViewController* split_view_controller = SplitViewController::Get(window);
@@ -547,9 +547,9 @@
 
   // Change window state and bounds to the snapped window state and bounds.
   UpdateWindow(window_state,
-               snap_event_type == WM_EVENT_SNAP_LEFT
-                   ? WindowStateType::kLeftSnapped
-                   : WindowStateType::kRightSnapped,
+               snap_event_type == WM_EVENT_SNAP_PRIMARY
+                   ? WindowStateType::kPrimarySnapped
+                   : WindowStateType::kSecondarySnapped,
                /*animated=*/false);
 }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.h b/ash/wm/tablet_mode/tablet_mode_window_state.h
index baa58f52..b55978f 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.h
@@ -72,9 +72,9 @@
   chromeos::WindowStateType GetMaximizedOrCenteredWindowType(
       WindowState* window_state);
 
-  // If |target_state| is LEFT/RIGHT_SNAPPED and the window can be snapped,
-  // returns |target_state|. Otherwise depending on the capabilities of the
-  // window either returns |WindowStateType::kMaximized| or
+  // If |target_state| is PRIMARY/SECONDARY_SNAPPED and the window can be
+  // snapped, returns |target_state|. Otherwise depending on the capabilities
+  // of the window either returns |WindowStateType::kMaximized| or
   // |WindowStateType::kNormal|.
   chromeos::WindowStateType GetSnappedWindowStateType(
       WindowState* window_state,
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc
index c88f457..b687e59 100644
--- a/ash/wm/toplevel_window_event_handler_unittest.cc
+++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -524,7 +524,7 @@
 
   // Verify that the window has moved after the gesture.
   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
-  EXPECT_EQ(WindowStateType::kRightSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, window_state->GetStateType());
 
   old_bounds = target->bounds();
 
@@ -536,7 +536,7 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
 
   window_state->Restore();
   gfx::Rect bounds_before_maximization = target->bounds();
@@ -595,7 +595,7 @@
 
   // Verify that the window has moved after the gesture.
   EXPECT_NE(old_bounds.ToString(), target->bounds().ToString());
-  EXPECT_EQ(WindowStateType::kRightSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, window_state->GetStateType());
 }
 
 // Tests that a gesture cannot minimize an unminimizeable window.
@@ -1088,7 +1088,7 @@
   // Snap the window to the right.
   WindowState* window_state = WindowState::Get(w1.get());
   ASSERT_TRUE(window_state->CanSnap());
-  const WMEvent event(WM_EVENT_CYCLE_SNAP_RIGHT);
+  const WMEvent event(WM_EVENT_CYCLE_SNAP_SECONDARY);
   window_state->OnWMEvent(&event);
   ASSERT_TRUE(window_state->IsSnapped());
 
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 0ddba1b..abb03694 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -263,8 +263,8 @@
 }
 
 bool WindowState::IsSnapped() const {
-  return GetStateType() == WindowStateType::kLeftSnapped ||
-         GetStateType() == WindowStateType::kRightSnapped;
+  return GetStateType() == WindowStateType::kPrimarySnapped ||
+         GetStateType() == WindowStateType::kSecondarySnapped;
 }
 
 bool WindowState::IsPinned() const {
@@ -502,8 +502,9 @@
 
   const WMEventType type = event->type();
   // Initializes |snapped_width_ratio_| whenever |event| is snapping event.
-  if (type == WM_EVENT_SNAP_LEFT || type == WM_EVENT_SNAP_RIGHT ||
-      type == WM_EVENT_CYCLE_SNAP_LEFT || type == WM_EVENT_CYCLE_SNAP_RIGHT) {
+  if (type == WM_EVENT_SNAP_PRIMARY || type == WM_EVENT_SNAP_SECONDARY ||
+      type == WM_EVENT_CYCLE_SNAP_PRIMARY ||
+      type == WM_EVENT_CYCLE_SNAP_SECONDARY) {
     // Since |UpdateSnappedWidthRatio()| is called post WMEvent taking effect,
     // |window_|'s bounds is in a correct state for ratio update.
     snapped_width_ratio_ =
@@ -672,9 +673,9 @@
     bounds->set_width(
         static_cast<int>(*snapped_width_ratio_ * maximized_bounds.width()));
   }
-  if (GetStateType() == WindowStateType::kLeftSnapped)
+  if (GetStateType() == WindowStateType::kPrimarySnapped)
     bounds->set_x(maximized_bounds.x());
-  else if (GetStateType() == WindowStateType::kRightSnapped)
+  else if (GetStateType() == WindowStateType::kSecondarySnapped)
     bounds->set_x(maximized_bounds.right() - bounds->width());
   bounds->set_y(maximized_bounds.y());
   bounds->set_height(maximized_bounds.height());
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc
index 38105f7..025d074e 100644
--- a/ash/wm/window_state_unittest.cc
+++ b/ash/wm/window_state_unittest.cc
@@ -75,7 +75,7 @@
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   gfx::Rect expected = gfx::Rect(kPrimaryDisplayWorkAreaBounds.x(),
                                  kPrimaryDisplayWorkAreaBounds.y(),
@@ -83,7 +83,7 @@
                                  kPrimaryDisplayWorkAreaBounds.height());
   EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
 
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_right);
   expected.set_x(kPrimaryDisplayWorkAreaBounds.right() - expected.width());
   EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
@@ -119,7 +119,7 @@
   delegate.set_minimum_size(gfx::Size(kWorkAreaBounds.width() - 1, 0));
   WindowState* window_state = WindowState::Get(window.get());
   EXPECT_TRUE(window_state->CanSnap());
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_right);
   gfx::Rect expected =
       gfx::Rect(kWorkAreaBounds.x() + 1, kWorkAreaBounds.y(),
@@ -380,9 +380,9 @@
       &delegate, -1, gfx::Rect(100, 100, 100, 100)));
   delegate.set_window_component(HTRIGHT);
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent cycle_snap_left(WM_EVENT_CYCLE_SNAP_LEFT);
+  const WMEvent cycle_snap_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state->OnWMEvent(&cycle_snap_left);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect expected =
       gfx::Rect(kWorkAreaBounds.x(), kWorkAreaBounds.y(),
                 kWorkAreaBounds.width() / 2, kWorkAreaBounds.height());
@@ -399,7 +399,7 @@
   generator->ReleaseLeftButton();
   expected.set_width(expected.width() + kIncreasedWidth);
   EXPECT_EQ(expected, window->GetBoundsInScreen());
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   EXPECT_EQ(0.75f, *window_state->snapped_width_ratio());
 
   // Another cycle snap left event will restore window state to normal.
@@ -410,7 +410,7 @@
   // Another cycle snap left event will snap window and reset snapped width
   // ratio.
   window_state->OnWMEvent(&cycle_snap_left);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   EXPECT_EQ(0.5f, *window_state->snapped_width_ratio());
 }
 
@@ -432,16 +432,16 @@
           .Build();
   delegate.set_window_component(HTCAPTION);
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent cycle_snap_left(WM_EVENT_CYCLE_SNAP_LEFT);
-  window_state->OnWMEvent(&cycle_snap_left);
+  const WMEvent cycle_snap_primary(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  window_state->OnWMEvent(&cycle_snap_primary);
 
-  // Snap window to the left.
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  // Snap window to primary position (left).
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect expected =
       gfx::Rect(kWorkAreaBounds.x(), kWorkAreaBounds.y(),
                 kWorkAreaBounds.width() / 2, kWorkAreaBounds.height());
   // Wait for the snapped animation to complete and test that the window bound
-  // is left-snapped and the snap width ratio is updated.
+  // is primary-snapped and the snap width ratio is updated.
   window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
                                        base::TimeDelta::FromSeconds(1));
   EXPECT_EQ(expected, window->GetBoundsInScreen());
@@ -477,9 +477,9 @@
   gfx::Rect restore_bounds = window->GetBoundsInScreen();
   restore_bounds.set_width(restore_bounds.width() + 1);
   window_state->SetRestoreBoundsInScreen(restore_bounds);
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_right);
   EXPECT_NE(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
   EXPECT_EQ(restore_bounds.ToString(),
@@ -516,7 +516,7 @@
   window->Show();
 
   window_state->Maximize();
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_right);
 
   const gfx::Rect kWorkAreaBounds =
@@ -881,14 +881,14 @@
   EXPECT_TRUE(window_state->IsNormalStateType());
   EXPECT_TRUE(window->GetTransparent());
 
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   EXPECT_FALSE(window->GetTransparent());
 
   window_state->Restore();
   EXPECT_TRUE(window->GetTransparent());
 
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_left);
   EXPECT_FALSE(window->GetTransparent());
 
diff --git a/ash/wm/wm_event.cc b/ash/wm/wm_event.cc
index 3d95ced..8b2db4e 100644
--- a/ash/wm/wm_event.cc
+++ b/ash/wm/wm_event.cc
@@ -33,8 +33,8 @@
     case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
     case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
     case WM_EVENT_TOGGLE_FULLSCREEN:
-    case WM_EVENT_CYCLE_SNAP_LEFT:
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
+    case WM_EVENT_CYCLE_SNAP_PRIMARY:
+    case WM_EVENT_CYCLE_SNAP_SECONDARY:
       return true;
     default:
       break;
@@ -70,8 +70,8 @@
     case WM_EVENT_MAXIMIZE:
     case WM_EVENT_MINIMIZE:
     case WM_EVENT_FULLSCREEN:
-    case WM_EVENT_SNAP_LEFT:
-    case WM_EVENT_SNAP_RIGHT:
+    case WM_EVENT_SNAP_PRIMARY:
+    case WM_EVENT_SNAP_SECONDARY:
     case WM_EVENT_SHOW_INACTIVE:
     case WM_EVENT_PIN:
     case WM_EVENT_TRUSTED_PIN:
diff --git a/ash/wm/wm_event.h b/ash/wm/wm_event.h
index 15e9b5d4..e02ff46 100644
--- a/ash/wm/wm_event.h
+++ b/ash/wm/wm_event.h
@@ -27,8 +27,15 @@
   WM_EVENT_MAXIMIZE,
   WM_EVENT_MINIMIZE,
   WM_EVENT_FULLSCREEN,
-  WM_EVENT_SNAP_LEFT,
-  WM_EVENT_SNAP_RIGHT,
+  // PRIMARY is left in primary landscape orientation and right in secondary
+  // landscape orientation. If |kVerticalSplitScreen| is enabled, PRIMARY is
+  // top in primary portrait orientation and SECONDARY is bottom in secondary
+  // portrait orientation. If not, in the clamshell mode, PRIMARY is left and
+  // SECONDARY is right.
+  WM_EVENT_SNAP_PRIMARY,
+  // SECONDARY is the opposite position of PRIMARY, i.e. if PRIMARY is left,
+  // SECONDARY is right.
+  WM_EVENT_SNAP_SECONDARY,
 
   // A window is requested to be the given bounds. The request may or
   // may not be fulfilled depending on the requested bounds and window's
@@ -56,17 +63,17 @@
   // A user requested to toggle fullscreen state.
   WM_EVENT_TOGGLE_FULLSCREEN,
 
-  // A user requested a cycle of snap left.
+  // A user requested a cycle of snap primary (left).
   // The way this event is processed is the current window state is used as
   // the starting state. Assuming normal window start state; if the window can
-  // be snapped left, snap it; otherwise progress to next state. If the
-  // window can be restored; and this isn't the entry condition restore it;
+  // be snapped primary (left), snap it; otherwise progress to next state. If
+  // the window can be restored; and this isn't the entry condition restore it;
   // otherwise apply the bounce animation to the window.
-  WM_EVENT_CYCLE_SNAP_LEFT,
+  WM_EVENT_CYCLE_SNAP_PRIMARY,
 
-  // A user requested a cycle of snap right.
-  // See decription of WM_EVENT_CYCLE_SNAP_LEFT.
-  WM_EVENT_CYCLE_SNAP_RIGHT,
+  // A user requested a cycle of snap secondary (right).
+  // See description of WM_EVENT_CYCLE_SNAP_PRIMARY.
+  WM_EVENT_CYCLE_SNAP_SECONDARY,
 
   // A user requested to center a window.
   WM_EVENT_CENTER,
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index 2bd5fca..40fb7be 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -598,17 +598,17 @@
       &delegate1, -1, gfx::Rect(100, 100, 100, 100)));
   delegate1.set_window_component(HTRIGHT);
   WindowState* w1_state = WindowState::Get(w1.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   w1_state->OnWMEvent(&snap_left);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, w1_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, w1_state->GetStateType());
   aura::test::TestWindowDelegate delegate2;
   std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate(
       &delegate2, -2, gfx::Rect(100, 100, 100, 100)));
   delegate2.set_window_component(HTRIGHT);
   WindowState* w2_state = WindowState::Get(w2.get());
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   w2_state->OnWMEvent(&snap_right);
-  EXPECT_EQ(WindowStateType::kRightSnapped, w2_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, w2_state->GetStateType());
   EXPECT_EQ(0.5f, *w1_state->snapped_width_ratio());
   EXPECT_EQ(0.5f, *w2_state->snapped_width_ratio());
 
@@ -640,9 +640,9 @@
   generator->ReleaseLeftButton();
 
   // Check snapped states and bounds.
-  EXPECT_EQ(WindowStateType::kLeftSnapped, w1_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, w1_state->GetStateType());
   EXPECT_EQ(gfx::Rect(0, 0, 300, bottom_inset), w1->bounds());
-  EXPECT_EQ(WindowStateType::kRightSnapped, w2_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kSecondarySnapped, w2_state->GetStateType());
   EXPECT_EQ(gfx::Rect(300, 0, 100, bottom_inset), w2->bounds());
   EXPECT_EQ(0.75f, *w1_state->snapped_width_ratio());
   EXPECT_EQ(0.25f, *w2_state->snapped_width_ratio());
diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc
index 5007cc61..db760747 100644
--- a/ash/wm/workspace/workspace_event_handler_unittest.cc
+++ b/ash/wm/workspace/workspace_event_handler_unittest.cc
@@ -215,7 +215,7 @@
                                       .work_area();
 
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent snap_event(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
 
   gfx::Rect snapped_bounds_in_screen = window->GetBoundsInScreen();
@@ -231,7 +231,7 @@
                                      window.get());
   delegate.set_window_component(HTTOP);
   generator.DoubleClickLeftButton();
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   EXPECT_EQ(snapped_bounds_in_screen.ToString(),
             window->GetBoundsInScreen().ToString());
 
@@ -364,7 +364,7 @@
   EXPECT_EQ(restore_bounds.ToString(), window->bounds().ToString());
 
   // 3) Double clicking a snapped window should maximize.
-  const WMEvent snap_event(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   EXPECT_TRUE(window_state->IsSnapped());
   generator.MoveMouseTo(window->GetBoundsInRootWindow().CenterPoint());
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 18de3d6..066da2b 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -569,9 +569,9 @@
   WindowState* window_state = WindowState::Get(window.get());
   gfx::Insets insets(0, 0, 56, 0);
   Shell::Get()->SetDisplayWorkAreaInsets(window.get(), insets);
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   const gfx::Rect kWorkAreaBounds = GetPrimaryDisplay().work_area();
   gfx::Rect expected_bounds =
       gfx::Rect(kWorkAreaBounds.x(), kWorkAreaBounds.y(),
@@ -601,7 +601,7 @@
   std::unique_ptr<aura::Window> window1(
       CreateTestWindow(gfx::Rect(10, 20, 100, 200)));
   WindowState* window1_state = WindowState::Get(window1.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window1_state->OnWMEvent(&snap_left);
   const gfx::Rect work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
@@ -612,7 +612,7 @@
   std::unique_ptr<aura::Window> window2(
       CreateTestWindow(gfx::Rect(10, 20, 100, 200)));
   WindowState* window2_state = WindowState::Get(window2.get());
-  const WMEvent snap_right(WM_EVENT_SNAP_RIGHT);
+  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window2_state->OnWMEvent(&snap_right);
   const gfx::Rect expected_right_snapped_bounds =
       gfx::Rect(work_area.right() - work_area.width() / 2, work_area.y(),
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 5c355b39..6ea6339 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -335,7 +335,7 @@
   // Other state types either create a different window resizer, or none at all.
   std::vector<WindowStateType> draggable_states = {
       WindowStateType::kDefault, WindowStateType::kNormal,
-      WindowStateType::kLeftSnapped, WindowStateType::kRightSnapped,
+      WindowStateType::kPrimarySnapped, WindowStateType::kSecondarySnapped,
       WindowStateType::kMaximized};
   DCHECK(base::Contains(draggable_states, state));
 #endif
@@ -375,9 +375,9 @@
   area.Inset(insets);
 
   if (location_in_screen.x() <= area.x())
-    return WorkspaceWindowResizer::SnapType::kLeft;
+    return WorkspaceWindowResizer::SnapType::kPrimary;
   else if (location_in_screen.x() >= area.right() - 1)
-    return WorkspaceWindowResizer::SnapType::kRight;
+    return WorkspaceWindowResizer::SnapType::kSecondary;
   else if (location_in_screen.y() <= area.y())
     return WorkspaceWindowResizer::SnapType::kMaximize;
 
@@ -710,12 +710,12 @@
     // metrics recording inside WindowState::OnWMEvent.
     WMEventType type;
     switch (snap_type_) {
-      case SnapType::kLeft:
-        type = WM_EVENT_SNAP_LEFT;
+      case SnapType::kPrimary:
+        type = WM_EVENT_SNAP_PRIMARY;
         base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeLeft"));
         break;
-      case SnapType::kRight:
-        type = WM_EVENT_SNAP_RIGHT;
+      case SnapType::kSecondary:
+        type = WM_EVENT_SNAP_SECONDARY;
         base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeRight"));
         break;
       case SnapType::kMaximize:
@@ -857,10 +857,11 @@
     } else if (event->details().velocity_x() >
                kMinHorizVelocityForWindowSwipe) {
       SetWindowStateTypeFromGesture(GetTarget(),
-                                    WindowStateType::kRightSnapped);
+                                    WindowStateType::kSecondarySnapped);
     } else if (event->details().velocity_x() <
                -kMinHorizVelocityForWindowSwipe) {
-      SetWindowStateTypeFromGesture(GetTarget(), WindowStateType::kLeftSnapped);
+      SetWindowStateTypeFromGesture(GetTarget(),
+                                    WindowStateType::kPrimarySnapped);
     }
   } else {
     DCHECK_EQ(event->type(), ui::ET_GESTURE_SWIPE);
@@ -878,9 +879,10 @@
       SetWindowStateTypeFromGesture(GetTarget(), WindowStateType::kMaximized);
     } else if (event->details().swipe_right()) {
       SetWindowStateTypeFromGesture(GetTarget(),
-                                    WindowStateType::kRightSnapped);
+                                    WindowStateType::kSecondarySnapped);
     } else {
-      SetWindowStateTypeFromGesture(GetTarget(), WindowStateType::kLeftSnapped);
+      SetWindowStateTypeFromGesture(GetTarget(),
+                                    WindowStateType::kPrimarySnapped);
     }
   }
   event->StopPropagation();
@@ -1337,11 +1339,11 @@
 
   gfx::Rect phantom_bounds;
   switch (snap_type_) {
-    case SnapType::kLeft:
+    case SnapType::kPrimary:
       phantom_bounds =
           GetDefaultLeftSnappedWindowBounds(display.work_area(), GetTarget());
       break;
-    case SnapType::kRight:
+    case SnapType::kSecondary:
       phantom_bounds =
           GetDefaultRightSnappedWindowBounds(display.work_area(), GetTarget());
       break;
@@ -1393,8 +1395,8 @@
   // Change |snap_type| to none if the requested snap type is not compatible
   // with the window.
   switch (snap_type) {
-    case SnapType::kLeft:
-    case SnapType::kRight:
+    case SnapType::kPrimary:
+    case SnapType::kSecondary:
       if (!window_state()->CanSnap())
         snap_type = SnapType::kNone;
       break;
@@ -1411,11 +1413,11 @@
 bool WorkspaceWindowResizer::AreBoundsValidSnappedBounds(
     WindowStateType snapped_type,
     const gfx::Rect& bounds_in_parent) const {
-  DCHECK(snapped_type == WindowStateType::kLeftSnapped ||
-         snapped_type == WindowStateType::kRightSnapped);
+  DCHECK(snapped_type == WindowStateType::kPrimarySnapped ||
+         snapped_type == WindowStateType::kSecondarySnapped);
   gfx::Rect snapped_bounds =
       screen_util::GetDisplayWorkAreaBoundsInParent(GetTarget());
-  if (snapped_type == WindowStateType::kRightSnapped)
+  if (snapped_type == WindowStateType::kSecondarySnapped)
     snapped_bounds.set_x(snapped_bounds.right() - bounds_in_parent.width());
   snapped_bounds.set_width(bounds_in_parent.width());
   return bounds_in_parent == snapped_bounds;
@@ -1442,17 +1444,17 @@
         window_state->Maximize();
       }
       break;
-    case WindowStateType::kLeftSnapped:
+    case WindowStateType::kPrimarySnapped:
       if (window_state->CanSnap()) {
         window_state->SetRestoreBoundsInParent(restore_bounds_for_gesture_);
-        const WMEvent event(WM_EVENT_SNAP_LEFT);
+        const WMEvent event(WM_EVENT_SNAP_PRIMARY);
         window_state->OnWMEvent(&event);
       }
       break;
-    case WindowStateType::kRightSnapped:
+    case WindowStateType::kSecondarySnapped:
       if (window_state->CanSnap()) {
         window_state->SetRestoreBoundsInParent(restore_bounds_for_gesture_);
-        const WMEvent event(WM_EVENT_SNAP_RIGHT);
+        const WMEvent event(WM_EVENT_SNAP_SECONDARY);
         window_state->OnWMEvent(&event);
       }
       break;
diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h
index ab9d6ba1..cd7f3ee 100644
--- a/ash/wm/workspace/workspace_window_resizer.h
+++ b/ash/wm/workspace/workspace_window_resizer.h
@@ -30,7 +30,7 @@
 class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
  public:
   // Possible states the window can end up in after a drag is complete.
-  enum class SnapType { kLeft, kRight, kMaximize, kNone };
+  enum class SnapType { kPrimary, kSecondary, kMaximize, kNone };
 
   // Min height we'll force on screen when dragging the caption.
   // TODO: this should come from a property on the window.
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index 6361946..e36d40b 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -670,9 +670,9 @@
   const gfx::Rect kInitialBounds(100, 100, 100, 100);
   window_->SetBounds(kInitialBounds);
   window_->Show();
-  const WMEvent snap_event(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect snapped_bounds = window_->bounds();
   EXPECT_NE(snapped_bounds.ToString(), kInitialBounds.ToString());
   EXPECT_EQ(kInitialBounds, window_state->GetRestoreBoundsInParent());
@@ -694,9 +694,9 @@
   window_->SetBounds(kInitialBounds);
   window_->Show();
 
-  const WMEvent snap_event(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
-  EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+  EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect snapped_bounds = window_->bounds();
   EXPECT_NE(snapped_bounds.ToString(), kInitialBounds.ToString());
   EXPECT_EQ(kInitialBounds, window_state->GetRestoreBoundsInParent());
@@ -708,7 +708,7 @@
         CreateResizerForTest(window_.get(), gfx::Point(), HTRIGHT);
     resizer->Drag(CalculateDragPoint(*resizer, 10, 0), 0);
     resizer->CompleteDrag();
-    EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+    EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
     snapped_bounds.Inset(0, 0, -10, 0);
     EXPECT_EQ(snapped_bounds.ToString(), window_->bounds().ToString());
     EXPECT_EQ(kInitialBounds, window_state->GetRestoreBoundsInParent());
@@ -722,7 +722,7 @@
     resizer->Drag(CalculateDragPoint(*resizer, 0, -30), 0);
     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
     resizer->CompleteDrag();
-    EXPECT_EQ(WindowStateType::kLeftSnapped, window_state->GetStateType());
+    EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
     EXPECT_EQ(snapped_bounds.ToString(), window_->bounds().ToString());
     EXPECT_EQ(kInitialBounds, window_state->GetRestoreBoundsInParent());
   }
@@ -2049,7 +2049,7 @@
   EXPECT_EQ(window_size, touch_resize_window_->bounds().size());
 
   // Snap a window and do the same test.
-  const WMEvent snap_event(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   ASSERT_TRUE(window_state->IsSnapped());
 
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index fadaf7a..12ab86a 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -1271,7 +1271,7 @@
 
   // Left snap |window|.
   EXPECT_FALSE(window_state->bounds_changed_by_user());
-  const WMEvent snap_left(WM_EVENT_SNAP_LEFT);
+  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   const gfx::Rect work_area =
       display::Screen::GetScreen()
diff --git a/base/allocator/allocator_shim.h b/base/allocator/allocator_shim.h
index 65a1668..39f23ffe 100644
--- a/base/allocator/allocator_shim.h
+++ b/base/allocator/allocator_shim.h
@@ -154,6 +154,9 @@
 #endif  // defined(OS_WIN)
 
 #if defined(OS_APPLE)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+void InitializeDefaultAllocatorPartitionRoot();
+#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 // On macOS, the allocator shim needs to be turned on during runtime.
 BASE_EXPORT void InitializeAllocatorShim();
 #endif  // defined(OS_APPLE)
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index 4250b730..767cd4b 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -582,8 +582,6 @@
 
 }  // extern "C"
 
-#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-
 #if defined(OS_APPLE)
 
 namespace base {
@@ -601,3 +599,5 @@
 }  // namespace base
 
 #endif  // defined(OS_APPLE)
+
+#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
diff --git a/base/allocator/allocator_shim_override_mac_default_zone.h b/base/allocator/allocator_shim_override_mac_default_zone.h
index e2e55d0..360e0fea 100644
--- a/base/allocator/allocator_shim_override_mac_default_zone.h
+++ b/base/allocator/allocator_shim_override_mac_default_zone.h
@@ -11,13 +11,12 @@
 #error This header must be included iff PartitionAlloc-Everywhere is enabled.
 #endif
 
-#include "base/notreached.h"
+#include "base/allocator/partition_allocator/partition_alloc_constants.h"
+#include "base/bits.h"
 
 namespace base {
 namespace allocator {
 
-void InitializeDefaultAllocatorPartitionRoot();
-
 namespace {
 
 // malloc_introspection_t's callback functions for our own zone
@@ -28,66 +27,88 @@
                                             vm_address_t zone_address,
                                             memory_reader_t reader,
                                             vm_range_recorder_t recorder) {
-  NOTREACHED();
+  // Should enumerate all memory regions allocated by this allocator, but not
+  // implemented just because of no use case for now.
   return KERN_FAILURE;
 }
 
 size_t MallocIntrospectionGoodSize(malloc_zone_t* zone, size_t size) {
-  return size;
+  return base::bits::AlignUp(size, base::kAlignment);
 }
 
 boolean_t MallocIntrospectionCheck(malloc_zone_t* zone) {
-  NOTREACHED();
+  // Should check the consistency of the allocator implementing this malloc
+  // zone, but not implemented just because of no use case for now.
   return true;
 }
 
 void MallocIntrospectionPrint(malloc_zone_t* zone, boolean_t verbose) {
-  NOTREACHED();
+  // Should print the current states of the zone for debugging / investigation
+  // purpose, but not implemented just because of no use case for now.
 }
 
 void MallocIntrospectionLog(malloc_zone_t* zone, void* address) {
-  NOTREACHED();
+  // Should enable logging of the activities on the given `address`, but not
+  // implemented just because of no use case for now.
 }
 
 void MallocIntrospectionForceLock(malloc_zone_t* zone) {
-  NOTREACHED();
+  // Called before fork(2) to acquire the lock.
+  //
+  // PartitionAllocMallocInitOnce() in
+  // //base/allocator/partition_allocator/partition_root.cc has already
+  // registered a set of fork handlers, so it's safe to do nothing here.
 }
 
 void MallocIntrospectionForceUnlock(malloc_zone_t* zone) {
-  NOTREACHED();
+  // Called in the parent process after fork(2) to release the lock.
+  //
+  // PartitionAllocMallocInitOnce() in
+  // //base/allocator/partition_allocator/partition_root.cc has already
+  // registered a set of fork handlers, so it's safe to do nothing here.
 }
 
 void MallocIntrospectionStatistics(malloc_zone_t* zone,
                                    malloc_statistics_t* stats) {
-  NOTREACHED();
+  // Should report the memory usage correctly, but not implemented just because
+  // of no use case for now.
+  stats->blocks_in_use = 0;
+  stats->size_in_use = 0;
+  stats->max_size_in_use = 0;  // High water mark of touched memory
+  stats->size_allocated = 0;   // Reserved in memory
 }
 
 boolean_t MallocIntrospectionZoneLocked(malloc_zone_t* zone) {
-  NOTREACHED();
+  // Should return true if the underlying PartitionRoot is locked, but not
+  // implemented just because this function seems not used effectively.
   return false;
 }
 
 boolean_t MallocIntrospectionEnableDischargeChecking(malloc_zone_t* zone) {
-  NOTREACHED();
+  // 'discharge' is not supported.
   return false;
 }
 
 void MallocIntrospectionDisableDischargeChecking(malloc_zone_t* zone) {
-  NOTREACHED();
+  // 'discharge' is not supported.
 }
 
 void MallocIntrospectionDischarge(malloc_zone_t* zone, void* memory) {
-  NOTREACHED();
+  // 'discharge' is not supported.
 }
 
 void MallocIntrospectionEnumerateDischargedPointers(
     malloc_zone_t* zone,
     void (^report_discharged)(void* memory, void* info)) {
-  NOTREACHED();
+  // 'discharge' is not supported.
 }
 
 void MallocIntrospectionReinitLock(malloc_zone_t* zone) {
-  NOTREACHED();
+  // Called in a child process after fork(2) to re-initialize the lock.
+  //
+  // PartitionAllocMallocInitOnce() in
+  // //base/allocator/partition_allocator/partition_root.cc has already
+  // registered a set of fork handlers, so it's safe to do nothing here.
 }
 
 void MallocIntrospectionPrintTask(task_t task,
@@ -95,14 +116,21 @@
                                   vm_address_t zone_address,
                                   memory_reader_t reader,
                                   print_task_printer_t printer) {
-  NOTREACHED();
+  // Should print the current states of another process's zone for debugging /
+  // investigation purpose, but not implemented just because of no use case
+  // for now.
 }
 
 void MallocIntrospectionTaskStatistics(task_t task,
                                        vm_address_t zone_address,
                                        memory_reader_t reader,
                                        malloc_statistics_t* stats) {
-  NOTREACHED();
+  // Should report the memory usage in another process's zone, but not
+  // implemented just because of no use case for now.
+  stats->blocks_in_use = 0;
+  stats->size_in_use = 0;
+  stats->max_size_in_use = 0;  // High water mark of touched memory
+  stats->size_allocated = 0;   // Reserved in memory
 }
 
 // malloc_zone_t's callback functions for our own zone
@@ -132,8 +160,7 @@
 }
 
 void MallocZoneDestroy(malloc_zone_t* zone) {
-  NOTREACHED();
-  IMMEDIATE_CRASH();
+  // No support to destroy the zone for now.
 }
 
 void* MallocZoneMemalign(malloc_zone_t* zone, size_t alignment, size_t size) {
@@ -194,8 +221,12 @@
   // `version` member indicates which APIs are supported in this zone.
   //   version >= 5: memalign is supported
   //   version >= 6: free_definite_size is supported
+  //   version >= 7: introspect's discharge family is supported
   //   version >= 8: pressure_relief is supported
+  //   version >= 9: introspect.reinit_lock is supported
   //   version >= 10: claimed_address is supported
+  //   version >= 11: introspect.print_task is supported
+  //   version >= 12: introspect.task_statistics is supported
   g_mac_malloc_zone.version = 6;
   g_mac_malloc_zone.zone_name = "PartitionAlloc";
   g_mac_malloc_zone.introspect = &g_mac_malloc_introspection;
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index 5377e0e..adfe2604 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -39,7 +39,7 @@
 
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
-#if defined(OS_LINUX)
+#if defined(OS_APPLE) || defined(OS_LINUX)
 
 // NO_THREAD_SAFETY_ANALYSIS: acquires the lock and doesn't release it, by
 // design.
@@ -92,7 +92,7 @@
   internal::ThreadCacheRegistry::Instance()
       .ForcePurgeAllThreadAfterForkUnsafe();
 }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_APPLE) || defined(OS_LINUX)
 
 std::atomic<bool> g_global_init_called;
 void PartitionAllocMallocInitOnce() {
@@ -102,7 +102,7 @@
   if (!g_global_init_called.compare_exchange_strong(expected, true))
     return;
 
-#if defined(OS_LINUX)
+#if defined(OS_APPLE) || defined(OS_LINUX)
   // When fork() is called, only the current thread continues to execute in the
   // child process. If the lock is held, but *not* by this thread when fork() is
   // called, we have a deadlock.
@@ -127,7 +127,7 @@
   int err =
       pthread_atfork(BeforeForkInParent, AfterForkInParent, AfterForkInChild);
   PA_CHECK(err == 0);
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_APPLE) || defined(OS_LINUX)
 }
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h
index ed4d7a8f..12fe21f 100644
--- a/base/allocator/partition_allocator/thread_cache.h
+++ b/base/allocator/partition_allocator/thread_cache.h
@@ -21,6 +21,12 @@
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 
+#if defined(ARCH_CPU_X86_64) && defined(PA_HAS_64_BITS_POINTERS)
+#include <algorithm>
+
+#include <emmintrin.h>
+#endif
+
 namespace base {
 
 namespace internal {
@@ -35,7 +41,20 @@
 //
 // On Android, we have to go through emutls, since this is always a shared
 // library, so don't bother.
-#if !(defined(OS_WIN) && defined(COMPONENT_BUILD)) && !defined(OS_ANDROID)
+//
+// On macOS and iOS with PartitionAlloc-Everywhere enabled, thread_local
+// allocates memory and it causes an infinite loop of ThreadCache::Get() ->
+// malloc_zone_malloc -> ShimMalloc -> ThreadCache::Get() -> ...
+// Exact stack trace is:
+//   libsystem_malloc.dylib`_malloc_zone_malloc
+//   libdyld.dylib`tlv_allocate_and_initialize_for_key
+//   libdyld.dylib`tlv_get_addr
+//   libbase.dylib`thread-local wrapper routine for
+//       base::internal::g_thread_cache
+//   libbase.dylib`base::internal::ThreadCache::Get()
+// where tlv_allocate_and_initialize_for_key performs memory allocation.
+#if !(defined(OS_WIN) && defined(COMPONENT_BUILD)) && !defined(OS_ANDROID) && \
+    !(defined(OS_APPLE) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC))
 #define PA_THREAD_CACHE_FAST_TLS
 #endif
 
@@ -434,6 +453,52 @@
 }
 
 ALWAYS_INLINE void ThreadCache::PutInBucket(Bucket& bucket, void* slot_start) {
+#if defined(ARCH_CPU_X86_64) && defined(PA_HAS_64_BITS_POINTERS)
+  // We see freelist corruption crashes happening in the wild.  These are likely
+  // due to out-of-bounds accesses in the previous slot, or to a Use-After-Free
+  // somewhere in the code.
+  //
+  // The issue is that we detect the UaF far away from the place where it
+  // happens. As a consequence, we should try to make incorrect code crash as
+  // early as possible. Poisoning memory at free() time works for UaF, but it
+  // was seen in the past to incur a high performance cost.
+  //
+  // Here, only poison the current cacheline, which we are touching anyway.
+  // TODO(lizeb): Make sure this does not hurt performance.
+
+  // Everything below requires this aligment.
+  static_assert(kAlignment == 16, "");
+
+#if HAS_BUILTIN(__builtin_assume_aligned)
+  uintptr_t address = reinterpret_cast<uintptr_t>(
+      __builtin_assume_aligned(slot_start, kAlignment));
+#else
+  uintptr_t address = reinterpret_cast<uintptr_t>(slot_start);
+#endif
+
+  // We assume that the cacheline size is 64 byte, which is true on all x86_64
+  // CPUs as of 2021.
+  //
+  // The pointer is always 16 bytes aligned, so its start address is always == 0
+  // % 16. Its distance to the next cacheline is 64 - ((address & 63) / 16) *
+  // 16.
+  int distance_to_next_cacheline_in_16_bytes = 4 - (address >> 4) & 3;
+  int slot_size_remaining_in_16_bytes =
+      std::min(bucket.slot_size / 16, distance_to_next_cacheline_in_16_bytes);
+
+  __m128i* address_aligned = reinterpret_cast<__m128i*>(address);
+  // Not a random value. If set to 0, then the compiler is "smart enough" to
+  // replace the loop below with a call to memset()@plt, which is not so great
+  // when trying to zero an integer multiple of 16 bytes, aligned on a 16 byte
+  // boundary.  Various ways to defeat that are brittle, to better make sure
+  // that the loop doesn't fit memset()'s use cases.
+  __m128i value = _mm_set1_epi32(0xdeadbeef);
+  for (auto i = 0; i < slot_size_remaining_in_16_bytes; i++) {
+    _mm_store_si128(address_aligned, value);
+    address_aligned += 1;
+  }
+#endif  // defined(ARCH_CPU_X86_64) && defined(PA_HAS_64_BITS_POINTERS)
+
   auto* entry = PartitionFreelistEntry::InitForThreadCache(
       slot_start, bucket.freelist_head);
   bucket.freelist_head = entry;
diff --git a/base/values.cc b/base/values.cc
index 230b223..e9ffb074 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1681,12 +1681,6 @@
   list().emplace_back(in_value);
 }
 
-void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
-  list().reserve(list().size() + in_values.size());
-  for (const auto& in_value : in_values)
-    list().emplace_back(in_value);
-}
-
 bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) {
   DCHECK(in_value);
   if (index > list().size())
diff --git a/base/values.h b/base/values.h
index 6562ef5..2acd617 100644
--- a/base/values.h
+++ b/base/values.h
@@ -917,8 +917,6 @@
   void AppendInteger(int in_value);
   void AppendString(StringPiece in_value);
   void AppendString(const std::u16string& in_value);
-  // DEPRECATED, use `Value::Append()` in a loop instead.
-  void AppendStrings(const std::vector<std::string>& in_values);
 
   using Value::Insert;
   // Insert a Value at index.
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 95c9f26..c5cab6d4 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -2423,14 +2423,14 @@
   EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("list", nullptr));
   EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("DNE", nullptr));
 
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("bool", nullptr));
-  EXPECT_TRUE(main_dict.GetIntegerWithoutPathExpansion("int", nullptr));
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("double", nullptr));
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("string", nullptr));
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("binary", nullptr));
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("dict", nullptr));
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("list", nullptr));
-  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("DNE", nullptr));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("bool"));
+  EXPECT_NE(absl::nullopt, main_dict.FindIntKey("int"));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("double"));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("string"));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("binary"));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("dict"));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("list"));
+  EXPECT_EQ(absl::nullopt, main_dict.FindIntKey("DNE"));
 
   EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("bool", nullptr));
   EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("int", nullptr));
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index 8a668e7..48409de 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -121,11 +121,6 @@
       'must be identical.')
 
   input_opts.add_argument(
-      '--support-zh-hk',
-      action='store_true',
-      help='Use zh-rTW resources for zh-rHK.')
-
-  input_opts.add_argument(
       '--debuggable',
       action='store_true',
       help='Whether to add android:debuggable="true".')
@@ -288,20 +283,6 @@
       yield os.path.join(root, f)
 
 
-def _DuplicateZhResources(resource_dirs, path_info):
-  """Duplicate Taiwanese resources into Hong-Kong specific directory."""
-  for resource_dir in resource_dirs:
-    # We use zh-TW resources for zh-HK (if we have zh-TW resources).
-    for path in _IterFiles(resource_dir):
-      if 'zh-rTW' in path:
-        hk_path = path.replace('zh-rTW', 'zh-rHK')
-        build_utils.MakeDirectory(os.path.dirname(hk_path))
-        shutil.copyfile(path, hk_path)
-        path_info.RegisterRename(
-            os.path.relpath(path, resource_dir),
-            os.path.relpath(hk_path, resource_dir))
-
-
 def _RenameLocaleResourceDirs(resource_dirs, path_info):
   """Rename locale resource directories into standard names when necessary.
 
@@ -357,13 +338,11 @@
             os.path.relpath(path2, resource_dir))
 
 
-def _ToAndroidLocales(locale_allowlist, support_zh_hk):
+def _ToAndroidLocales(locale_allowlist):
   """Converts the list of Chrome locales to Android config locale qualifiers.
 
   Args:
     locale_allowlist: A list of Chromium locale names.
-    support_zh_hk: True if we need to support zh-HK by duplicating
-      the zh-TW strings.
   Returns:
     A set of matching Android config locale qualifier names.
   """
@@ -377,14 +356,7 @@
     language = locale.split('-')[0]
     ret.add(language)
 
-  # We don't actually support zh-HK in Chrome on Android, but we mimic the
-  # native side behavior where we use zh-TW resources when the locale is set to
-  # zh-HK. See https://crbug.com/780847.
-  if support_zh_hk:
-    assert not any('HK' in l for l in locale_allowlist), (
-        'Remove special logic if zh-HK is now supported (crbug.com/780847).')
-    ret.add('zh-rHK')
-  return set(ret)
+  return ret
 
 
 def _MoveImagesToNonMdpiFolders(res_root, path_info):
@@ -710,8 +682,7 @@
   # list provided by --locale-allowlist.
   wanted_locales = all_locales
   if options.locale_allowlist:
-    wanted_locales = _ToAndroidLocales(options.locale_allowlist,
-                                       options.support_zh_hk)
+    wanted_locales = _ToAndroidLocales(options.locale_allowlist)
 
   # Set B: shared resources locales, which is either set A
   # or the list provided by --shared-resources-allowlist-locales
@@ -723,7 +694,7 @@
             options.shared_resources_allowlist))
 
     shared_resources_locales = _ToAndroidLocales(
-        options.shared_resources_allowlist_locales, options.support_zh_hk)
+        options.shared_resources_allowlist_locales)
 
   # Remove any file that belongs to a locale not covered by
   # either A or B.
@@ -783,8 +754,6 @@
 
   logging.debug('Applying locale transformations')
   path_info = resource_utils.ResourceInfoFile()
-  if options.support_zh_hk:
-    _DuplicateZhResources(dep_subdirs, path_info)
   _RenameLocaleResourceDirs(dep_subdirs, path_info)
 
   logging.debug('Applying file-based exclusions')
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 5fd989b..11eb48cd 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2212,10 +2212,6 @@
   #     resources to put in the final output, even if aapt_locale_allowlist
   #     is defined to a smaller subset.
   #
-  #   support_zh_hk: (optional)
-  #     If true, support zh-HK in Chrome on Android by using the resources
-  #     from zh-TW. See https://crbug.com/780847.
-  #
   #   aapt_locale_allowlist: (optional)
   #     Restrict compiled locale-dependent resources to a specific allowlist.
   #     NOTE: This is a list of Chromium locale names, not Android ones.
@@ -2528,10 +2524,6 @@
           [ "--values-filter-rules=${invoker.resource_values_filter_rules}" ]
     }
 
-    if (defined(invoker.support_zh_hk) && invoker.support_zh_hk) {
-      _args += [ "--support-zh-hk" ]
-    }
-
     if (defined(invoker.include_resource)) {
       _rebased_include_resources =
           rebase_path(invoker.include_resource, root_build_dir)
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index c65ab979..d33240d 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2482,7 +2482,6 @@
                                "resources_config_paths",
                                "shared_resources",
                                "shared_resources_allowlist_locales",
-                               "support_zh_hk",
                                "uses_split",
                              ])
       short_resource_paths = _short_resource_paths
@@ -3498,7 +3497,6 @@
                                "static_library_provider",
                                "static_library_synchronized_proguard",
                                "strip_resource_names",
-                               "support_zh_hk",
                                "target_sdk_version",
                                "testonly",
                                "uncompress_dex",
@@ -3626,7 +3624,6 @@
                                "static_library_provider",
                                "static_library_synchronized_proguard",
                                "strip_resource_names",
-                               "support_zh_hk",
                                "target_sdk_version",
                                "testonly",
                                "uncompress_shared_libraries",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 96545ed..da03a90 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1623,6 +1623,14 @@
           "-Wno-non-c-typedef-for-linkage",
         ]
 
+        if (llvm_force_head_revision) {
+          # TODO(https://crbug.com/1203071): Clean up and enable.
+          cflags += [
+            "-Wno-unused-but-set-parameter",
+            "-Wno-unused-but-set-variable",
+          ]
+        }
+
         cflags_c += [
           # TODO(https://crbug.com/995993): Clean up and enable.
           "-Wno-implicit-fallthrough",
diff --git a/build/config/locales.gni b/build/config/locales.gni
index e94e162..1d57b877 100644
--- a/build/config/locales.gni
+++ b/build/config/locales.gni
@@ -14,26 +14,11 @@
 # |locales_without_pseudolocales|.
 
 # The following additional platform specific lists are created:
-# - |android_apk_locales| subset for Android based apk builds
 # - |android_bundle_locales_as_resources| locales formatted for XML output names
 # - |locales_as_mac_outputs| formated for mac output bundles
 # - |ios_packed_locales| subset for iOS
 # - |ios_packed_locales_as_mac_outputs| subset for iOS output
 
-# Android doesn't ship all locales in order to save space (but webview does).
-# http://crbug.com/369218
-android_apk_omitted_locales = [
-  "bn",
-  "et",
-  "gu",
-  "kn",
-  "ml",
-  "mr",
-  "ms",
-  "ta",
-  "te",
-]
-
 # Chrome on iOS only ships with a subset of the locales supported by other
 # version of Chrome as the corresponding locales are not supported by the
 # operating system (but for simplicity, the corresponding .pak files are
@@ -57,7 +42,6 @@
 # These list are defined even when not building for Android or iOS for the
 # sake of build/locale_tool.py. Ensure that GN doesn't complain about them
 # being unused.
-not_needed([ "android_apk_omitted_locales" ])
 not_needed([ "ios_unsupported_locales" ])
 
 # Superset of all locales used in Chrome with platform specific changes noted.
@@ -183,11 +167,6 @@
 if (is_android) {
   locales = all_chrome_locales
 
-  # Android doesn't ship all locales on KitKat in order to save space
-  # (but webview does). http://crbug.com/369218
-  android_apk_locales = all_chrome_locales - android_bundle_only_locales -
-                        android_apk_omitted_locales
-
   # List for Android locale names in .xml exports. Note: needs to stay in sync
   # with |ToAndroidLocaleName| in build/android/gyp/util/resource_utils.py.
   #  - add r: (e.g. zh-HK -> zh-rHK )
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 92458ab..e2ba3a48 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-4.20210601.3.1
+4.20210602.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 92458ab..e2ba3a48 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-4.20210601.3.1
+4.20210602.1.1
diff --git a/build/locale_tool.py b/build/locale_tool.py
index cad51908..b5729d8 100755
--- a/build/locale_tool.py
+++ b/build/locale_tool.py
@@ -322,10 +322,9 @@
 ##########################################################################
 
 # Various list of locales that will be extracted from build/config/locales.gni
-# Do not use these directly, use ChromeLocales(), AndroidAPKOmittedLocales() and
-# IosUnsupportedLocales() instead to access these lists.
+# Do not use these directly, use ChromeLocales(), and IosUnsupportedLocales()
+# instead to access these lists.
 _INTERNAL_CHROME_LOCALES = []
-_INTERNAL_ANDROID_APK_OMITTED_LOCALES = []
 _INTERNAL_IOS_UNSUPPORTED_LOCALES = []
 
 
@@ -336,13 +335,6 @@
   return _INTERNAL_CHROME_LOCALES
 
 
-def AndroidAPKOmittedLocales():
-  """Return the list of locales omitted from Android APKs."""
-  if not _INTERNAL_ANDROID_APK_OMITTED_LOCALES:
-    _ExtractAllChromeLocalesLists()
-  return _INTERNAL_ANDROID_APK_OMITTED_LOCALES
-
-
 def IosUnsupportedLocales():
   """Return the list of locales that are unsupported on iOS."""
   if not _INTERNAL_IOS_UNSUPPORTED_LOCALES:
@@ -404,9 +396,6 @@
 # Write the locales lists to files in the output directory.
 _filename = root_build_dir + "/foo"
 write_file(_filename + ".locales", locales, "json")
-write_file(_filename + ".android_apk_omitted_locales",
-            android_apk_omitted_locales,
-            "json")
 write_file(_filename + ".ios_unsupported_locales",
             ios_unsupported_locales,
             "json")
@@ -461,10 +450,6 @@
     _INTERNAL_CHROME_LOCALES = _ReadJsonList(
         os.path.join(out_path, 'foo.locales'))
 
-    global _INTERNAL_ANDROID_APK_OMITTED_LOCALES
-    _INTERNAL_ANDROID_APK_OMITTED_LOCALES = _ReadJsonList(
-        os.path.join(out_path, 'foo.android_apk_omitted_locales'))
-
     global _INTERNAL_IOS_UNSUPPORTED_LOCALES
     _INTERNAL_IOS_UNSUPPORTED_LOCALES = _ReadJsonList(
         os.path.join(out_path, 'foo.ios_unsupported_locales'))
@@ -1286,9 +1271,8 @@
   description = 'List supported Chrome locales'
   long_description = r'''
 List locales of interest, by default this prints all locales supported by
-Chrome, but `--type=android_apk_omitted` can be used to print the list of
-locales omitted from Android APKs (but not app bundles), and
-`--type=ios_unsupported` for the list of locales unsupported on iOS.
+Chrome, but `--type=ios_unsupported` can be used for the list of locales
+unsupported on iOS.
 
 These values are extracted directly from build/config/locales.gni.
 
@@ -1299,7 +1283,6 @@
   # Maps type argument to a function returning the corresponding locales list.
   TYPE_MAP = {
       'all': ChromeLocales,
-      'android_apk_omitted': AndroidAPKOmittedLocales,
       'ios_unsupported': IosUnsupportedLocales,
   }
 
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc
index 169ff7b..d118886 100644
--- a/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -868,7 +868,9 @@
                    .InsertBeforeExtensionASCII(GetRendererSuffix()));
 }
 
-TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
+// TODO(michaelludwig): crbug.com/1143929 disable this test for skia roll and
+// then rebase expected image.
+TEST_P(LayerTreeHostFiltersPixelTest, DISABLED_RotatedDropShadowFilter) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(300, 300), SK_ColorWHITE);
 
diff --git a/chrome/PRESUBMIT.py b/chrome/PRESUBMIT.py
index e7bdbd11..3f4d409 100644
--- a/chrome/PRESUBMIT.py
+++ b/chrome/PRESUBMIT.py
@@ -8,6 +8,8 @@
 for more details about the presubmit API built into depot_tools.
 """
 
+USE_PYTHON3 = True
+
 import re
 
 INCLUDE_CPP_FILES_ONLY = (
diff --git a/chrome/PRESUBMIT_test.py b/chrome/PRESUBMIT_test.py
index 0ce9a769..595e20e 100755
--- a/chrome/PRESUBMIT_test.py
+++ b/chrome/PRESUBMIT_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2017 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.
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index fba2dd9..4a99266 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2006,13 +2006,7 @@
       renaming_sources = []
       renaming_destinations = []
 
-      # Only include all Android locales on bundle builds.
-      if (_is_bundle_module) {
-        _locales_list = locales
-      } else {
-        _locales_list = android_apk_locales
-      }
-      foreach(_locale, _locales_list) {
+      foreach(_locale, locales) {
         renaming_sources +=
             [ "$target_gen_dir/${_variant}_paks/locales/$_locale.pak" ]
         renaming_destinations += [ "locales/$_locale.pak" ]
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index f1cb16b..c485c30a 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -173,11 +173,6 @@
       product_config_java_packages = [ "org.chromium.chrome.browser" ]
     }
 
-    # Use zh-TW strings for zh-HK (https://crbug.com/780847).
-    if (!defined(support_zh_hk)) {
-      support_zh_hk = true
-    }
-
     # Android supports webp transparent resources properly since API level 18,
     # so this can only be activated for modern ones (which target API >= 21).
     if (!defined(png_to_webp)) {
@@ -190,18 +185,8 @@
     short_resource_paths = true
 
     if (!defined(aapt_locale_allowlist)) {
-      if (target_type == "android_apk") {
-        # For APKs, do not include the resource strings files from our
-        # omitted locale list in order to save size.
-        aapt_locale_allowlist = android_apk_locales
-      } else {
-        # For bundles, only include resource strings files from our full
-        # locale list, but nothing more.
-        aapt_locale_allowlist = locales
-
-        # zh_hk is supported in Android bundles.
-        support_zh_hk = false
-      }
+      # Include resource strings files only for supported locales.
+      aapt_locale_allowlist = locales
     }
 
     if (!defined(use_chromium_linker)) {
@@ -587,13 +572,6 @@
         uncompress_shared_libraries = true
       }
 
-      # Android N+ better supports multiple locales (https://crbug.com/780847).
-      if (defined(invoker.support_zh_hk)) {
-        support_zh_hk = invoker.support_zh_hk
-      } else {
-        support_zh_hk = false
-      }
-
       if (_is_bundle_module) {
         _pak_prefix += "_bundle_module"
       } else {
@@ -644,7 +622,6 @@
       "secondary_abi_shared_libraries",
       "secondary_native_lib_placeholders",
       "shared_libraries",
-      "support_zh_hk",
       "uncompress_shared_libraries",
       "use_chromium_linker",
       "use_modern_linker",
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
index a6f57fd8..fcd95a59 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
@@ -48,6 +48,7 @@
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Integration tests of the {@link StartSurface} for cases where there are no tabs. See {@link
@@ -112,7 +113,7 @@
     @Feature({"StartSurface"})
     // clang-format off
     @CommandLineFlags.Add({BASE_PARAMS + "/single"})
-    public void testShow_SingleAsHomepage_NoTabs() {
+    public void testShow_SingleAsHomepage_NoTabs() throws TimeoutException {
         // clang-format on
         CriteriaHelper.pollUiThread(
                 ()
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 52550a3..5c0cd615 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -38,8 +38,6 @@
 import static org.chromium.chrome.test.util.ViewUtils.waitForView;
 
 import android.os.Build;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
 import android.support.test.runner.lifecycle.Stage;
@@ -232,8 +230,12 @@
                 mLayoutChangedCallbackHelper.notifyCalled();
             }
         };
-        mActivityTestRule.getActivity().getLayoutManagerSupplier().addObserver(
-                (obs) -> { obs.addObserver(mLayoutObserver); });
+        mActivityTestRule.getActivity().getLayoutManagerSupplier().addObserver((manager) -> {
+            if (manager.getActiveLayout() != null) {
+                mCurrentlyActiveLayout = manager.getActiveLayout().getLayoutType();
+            }
+            manager.addObserver(mLayoutObserver);
+        });
     }
 
     @Test
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index c5e6f86..b34a404 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -667,8 +667,9 @@
                         if (getCompositorViewHolder() == null) return null;
                         return getCompositorViewHolder().getLayerTitleCache();
                     },
-                    mOverviewModeBehaviorSupplier, mLayoutStateProviderOneshotSupplier,
+                    mOverviewModeBehaviorSupplier,
                     mRootUiCoordinator::getTopUiThemeColorProvider);
+            mLayoutStateProviderOneshotSupplier.set(mLayoutManager);
             // clang-format on
             mOverviewModeController = mLayoutManager;
         }
@@ -686,8 +687,9 @@
                         if (getCompositorViewHolder() == null) return null;
                         return getCompositorViewHolder().getLayerTitleCache();
                     },
-                    mOverviewModeBehaviorSupplier, mLayoutStateProviderOneshotSupplier,
+                    mOverviewModeBehaviorSupplier,
                     mRootUiCoordinator::getTopUiThemeColorProvider);
+            mLayoutStateProviderOneshotSupplier.set(mLayoutManager);
             // clang-format on
             mOverviewModeController = mLayoutManager;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
index 3839a19..f039106 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -26,7 +26,6 @@
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.layouts.components.VirtualView;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
@@ -86,7 +85,6 @@
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param layerTitleCacheSupplier Supplier of the {@link LayerTitleCache}.
      * @param overviewModeBehaviorSupplier Supplier of the {@link OverviewModeBehavior}.
-     * @param layoutStateProviderOneshotSupplier Supplier of the {@link LayoutStateProvider}.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
      */
     public LayoutManagerChrome(LayoutManagerHost host, ViewGroup contentContainer,
@@ -94,10 +92,9 @@
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<LayerTitleCache> layerTitleCacheSupplier,
             OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier,
-            OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) {
         super(host, contentContainer, tabContentManagerSupplier, layerTitleCacheSupplier,
-                layoutStateProviderOneshotSupplier, topUiThemeColorProvider);
+                topUiThemeColorProvider);
         Context context = host.getContext();
         LayoutRenderHost renderHost = host.getLayoutRenderHost();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
index 16c6213..02941e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -14,7 +14,6 @@
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.compositor.layouts.phone.SimpleAnimationLayout;
 import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -42,7 +41,6 @@
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param layerTitleCacheSupplier Supplier of the {@link LayerTitleCache}.
      * @param overviewModeBehaviorSupplier Supplier of the {@link OverviewModeBehavior}.
-     * @param layoutStateProviderOneshotSupplier Supplier of the {@link LayoutStateProvider}.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
      */
     public LayoutManagerChromePhone(LayoutManagerHost host, ViewGroup contentContainer,
@@ -50,11 +48,9 @@
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<LayerTitleCache> layerTitleCacheSupplier,
             OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier,
-            OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) {
         super(host, contentContainer, true, startSurface, tabContentManagerSupplier,
-                layerTitleCacheSupplier, overviewModeBehaviorSupplier,
-                layoutStateProviderOneshotSupplier, topUiThemeColorProvider);
+                layerTitleCacheSupplier, overviewModeBehaviorSupplier, topUiThemeColorProvider);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
index 80fc087..556b5bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -13,7 +13,6 @@
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -40,18 +39,15 @@
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param layerTitleCacheSupplier Supplier of the {@link LayerTitleCache}.
      * @param overviewModeBehaviorSupplier Supplier of the {@link OverviewModeBehavior}.
-     * @param layoutStateProviderOneshotSupplier Supplier of the {@link LayoutStateProvider}.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
      */
     public LayoutManagerChromeTablet(LayoutManagerHost host, ViewGroup contentContainer,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<LayerTitleCache> layerTitleCacheSupplier,
             OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier,
-            OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) {
         super(host, contentContainer, false, null, tabContentManagerSupplier,
-                layerTitleCacheSupplier, overviewModeBehaviorSupplier,
-                layoutStateProviderOneshotSupplier, topUiThemeColorProvider);
+                layerTitleCacheSupplier, overviewModeBehaviorSupplier, topUiThemeColorProvider);
 
         mTabStripLayoutHelperManager = new StripLayoutHelperManager(host.getContext(), this,
                 mHost.getLayoutRenderHost(), () -> mTitleCache, layerTitleCacheSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
index 9423b8f..4c97f1d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
@@ -20,7 +20,6 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
-import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils;
@@ -37,7 +36,6 @@
 import org.chromium.chrome.browser.gesturenav.HistoryNavigationCoordinator;
 import org.chromium.chrome.browser.layouts.CompositorModelChangeProcessor;
 import org.chromium.chrome.browser.layouts.EventFilter;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.layouts.LayoutType;
 import org.chromium.chrome.browser.layouts.ManagedLayoutManager;
 import org.chromium.chrome.browser.layouts.SceneOverlay;
@@ -169,9 +167,6 @@
     /** A map of {@link SceneOverlay} to its position relative to the others. */
     private Map<Class, Integer> mOverlayOrderMap = new HashMap<>();
 
-    /** The supplier used to supply the LayoutStateProvider. */
-    private final OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderOneshotSupplier;
-
     /** The supplier of {@link ThemeColorProvider} for top UI. */
     private final Supplier<TopUiThemeColorProvider> mTopUiThemeColorProvider;
 
@@ -257,19 +252,15 @@
      * @param contentContainer A {@link ViewGroup} for Android views to be bound to.
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param layerTitleCacheSupplier A supplier of the cache of title textures.
-     * @param layoutStateProviderOneshotSupplier Supplier used to supply the {@link
-     *         LayoutStateProvider}.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
      */
     public LayoutManagerImpl(LayoutManagerHost host, ViewGroup contentContainer,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<LayerTitleCache> layerTitleCacheSupplier,
-            OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) {
         mHost = host;
         mPxToDp = 1.f / mHost.getContext().getResources().getDisplayMetrics().density;
         mTabContentManagerSupplier = tabContentManagerSupplier;
-        mLayoutStateProviderOneshotSupplier = layoutStateProviderOneshotSupplier;
         mLayerTitleCacheSupplier = layerTitleCacheSupplier;
         mTopUiThemeColorProvider = topUiThemeColorProvider;
         mContext = host.getContext();
@@ -298,8 +289,6 @@
 
         mFrameRequestSupplier =
                 new CompositorModelChangeProcessor.FrameRequestSupplier(this::requestUpdate);
-
-        mLayoutStateProviderOneshotSupplier.set(this);
     }
 
     /**
@@ -905,18 +894,22 @@
     public void startHiding(int nextTabId, boolean hintAtTabSelection) {
         requestUpdate();
         if (hintAtTabSelection) {
-            notifyObserversOnTabSelectionHinted(nextTabId);
-
             // TODO(crbug.com/1108496): Remove after migrates to LayoutStateObserver.
             for (SceneChangeObserver observer : mSceneChangeObservers) {
                 observer.onTabSelectionHinted(nextTabId);
             }
+
+            for (LayoutStateObserver observer : mLayoutObservers) {
+                observer.onTabSelectionHinted(nextTabId);
+            }
         }
 
         Layout layoutBeingHidden = getActiveLayout();
-        notifyObserversLayoutStartedHiding(layoutBeingHidden.getLayoutType(),
-                shouldShowToolbarAnimationOnHide(layoutBeingHidden, nextTabId),
-                shouldDelayHideAnimation(layoutBeingHidden));
+        for (LayoutStateObserver observer : mLayoutObservers) {
+            observer.onStartedHiding(layoutBeingHidden.getLayoutType(),
+                    shouldShowToolbarAnimationOnHide(layoutBeingHidden, nextTabId),
+                    shouldDelayHideAnimation(layoutBeingHidden));
+        }
     }
 
     @Override
@@ -926,7 +919,9 @@
         assert mNextActiveLayout != null : "Need to have a next active layout.";
         if (mNextActiveLayout != null) {
             // Notify LayoutObservers the active layout is finished hiding.
-            notifyObserversLayoutFinishedHiding(getActiveLayout().getLayoutType());
+            for (LayoutStateObserver observer : mLayoutObservers) {
+                observer.onFinishedHiding(getActiveLayout().getLayoutType());
+            }
 
             startShowing(mNextActiveLayout, true);
         }
@@ -935,7 +930,9 @@
     @Override
     public void doneShowing() {
         // Notify LayoutObservers the active layout is finished showing.
-        notifyObserversLayoutFinishedShowing(getActiveLayout().getLayoutType());
+        for (LayoutStateObserver observer : mLayoutObservers) {
+            observer.onFinishedShowing(getActiveLayout().getLayoutType());
+        }
     }
 
     /**
@@ -994,8 +991,10 @@
             observer.onSceneChange(getActiveLayout());
         }
 
-        notifyObserversLayoutStartedShowing(
-                layout.getLayoutType(), shouldShowToolbarAnimationOnShow(animate));
+        for (LayoutStateObserver observer : mLayoutObservers) {
+            observer.onStartedShowing(
+                    layout.getLayoutType(), shouldShowToolbarAnimationOnShow(animate));
+        }
     }
 
     /**
@@ -1012,6 +1011,11 @@
         return layout == mActiveLayout;
     }
 
+    @Override
+    public int getActiveLayoutType() {
+        return getActiveLayout() != null ? getActiveLayout().getLayoutType() : LayoutType.NONE;
+    }
+
     /**
      * Get a list of virtual views for accessibility.
      *
@@ -1125,48 +1129,6 @@
         mLayoutObservers.removeObserver(listener);
     }
 
-    protected final void notifyObserversLayoutStartedShowing(
-            @LayoutType int layoutType, boolean showToolbar) {
-        mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> {
-            for (LayoutStateObserver observer : mLayoutObservers) {
-                observer.onStartedShowing(layoutType, showToolbar);
-            }
-        });
-    }
-
-    protected final void notifyObserversLayoutFinishedShowing(@LayoutType int layoutType) {
-        mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> {
-            for (LayoutStateObserver observer : mLayoutObservers) {
-                observer.onFinishedShowing(layoutType);
-            }
-        });
-    }
-
-    protected final void notifyObserversLayoutStartedHiding(
-            @LayoutType int layoutType, boolean showToolbar, boolean delayAnimation) {
-        mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> {
-            for (LayoutStateObserver observer : mLayoutObservers) {
-                observer.onStartedHiding(layoutType, showToolbar, delayAnimation);
-            }
-        });
-    }
-
-    protected final void notifyObserversLayoutFinishedHiding(@LayoutType int layoutType) {
-        mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> {
-            for (LayoutStateObserver observer : mLayoutObservers) {
-                observer.onFinishedHiding(layoutType);
-            }
-        });
-    }
-
-    protected final void notifyObserversOnTabSelectionHinted(int tabId) {
-        mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> {
-            for (LayoutStateObserver observer : mLayoutObservers) {
-                observer.onTabSelectionHinted(tabId);
-            }
-        });
-    }
-
     protected boolean shouldShowToolbarAnimationOnShow(boolean isAnimate) {
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index 2a2d8b3..a93439bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -810,7 +810,9 @@
         } else if (itemId == R.id.contextmenu_direct_share_image) {
             recordContextMenuSelection(ContextMenuUma.Action.DIRECT_SHARE_IMAGE);
             mNativeDelegate.retrieveImageForShare(ContextMenuImageFormat.ORIGINAL, (Uri uri) -> {
-                ShareHelper.shareImage(getWindow(), ShareHelper.getLastShareComponentName(), uri);
+                ShareHelper.shareImage(getWindow(),
+                        Profile.fromWebContents(mItemDelegate.getWebContents()),
+                        ShareHelper.getLastShareComponentName(), uri);
             });
         } else if (itemId == R.id.contextmenu_open_in_chrome) {
             recordContextMenuSelection(ContextMenuUma.Action.OPEN_IN_CHROME);
@@ -893,7 +895,8 @@
     private void shareImage() {
         mNativeDelegate.retrieveImageForShare(ContextMenuImageFormat.ORIGINAL, (Uri imageUri) -> {
             if (!mShareDelegateSupplier.get().isSharingHubEnabled()) {
-                ShareHelper.shareImage(getWindow(), null, imageUri);
+                ShareHelper.shareImage(getWindow(),
+                        Profile.fromWebContents(mItemDelegate.getWebContents()), null, imageUri);
                 return;
             }
             ContentResolver contentResolver =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabColorProviderImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabColorProviderImpl.java
index ddc3b8f2..44e1172 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabColorProviderImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabColorProviderImpl.java
@@ -23,8 +23,7 @@
 import org.chromium.ui.util.ColorUtils;
 
 /**
- * ColorProvider implementation used for normal profiles, in some cases incognito
- * profiles.
+ * ColorProvider implementation used for normal profiles.
  */
 public final class CustomTabColorProviderImpl implements ColorProvider {
     private static final String TAG = "CustomTabColorPrvdr";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java
index 174a8267..abc768b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java
@@ -9,7 +9,6 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -79,7 +78,7 @@
                     if (mCompositorViewHolder.get() == null) return null;
                     return mCompositorViewHolder.get().getLayerTitleCache();
                 },
-                new OneshotSupplierImpl<>(), () -> mTopUiThemeColorProvider);
+                () -> mTopUiThemeColorProvider);
         // clang-format on
 
         mCompositorViewHolderInitializer.initializeCompositorContent(layoutDriver,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
index 4ad4e519..40439ce0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
@@ -48,19 +48,6 @@
 public class IncognitoCustomTabIntentDataProvider extends BrowserServicesIntentDataProvider {
     private static final int MAX_CUSTOM_MENU_ITEMS = 5;
 
-    // If set, the incognito icon is not shown. Only honored for first party requests.
-    public static final String EXTRA_HIDE_INCOGNITO_ICON =
-            "org.chromium.chrome.browser.customtabs.HIDE_INCOGNITO_ICON";
-
-    // If set, the colors match that of normal profiles. Only honored for first party requests.
-    public static final String EXTRA_USE_NORMAL_PROFILE_STYLE =
-            "org.chromium.chrome.browser.customtabs.USE_NORMAL_PROFILE_STYLE";
-
-    // If set, incognito is allowed regardless of the status of the feature. Only honored for first
-    // party requests.
-    public static final String EXTRA_FORCE_ENABLE_FOR_EXPERIMENT =
-            "org.chromium.chrome.browser.customtabs.FORCE_ENABLE_FOR_EXPERIMENT";
-
     private final Intent mIntent;
     private final CustomTabsSessionToken mSession;
     private final boolean mIsTrustedIntent;
@@ -70,7 +57,6 @@
     private final Drawable mCloseButtonIcon;
     private final boolean mShowShareItem;
     private final List<Pair<String, PendingIntent>> mMenuEntries = new ArrayList<>();
-    private final boolean mHideIncognitoIconOnToolbar;
 
     @Nullable
     private final String mUrlToLoad;
@@ -96,13 +82,7 @@
         mIsOpenedByChrome =
                 IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OPENED_BY_CHROME, false);
         // Only allow first-parties to change the styling.
-        final boolean useNormalProfileColors = isIntentFromFirstParty(intent)
-                && IntentUtils.safeGetBooleanExtra(intent, EXTRA_USE_NORMAL_PROFILE_STYLE, false);
-        mColorProvider = useNormalProfileColors
-                ? new CustomTabColorProviderImpl(intent, context, colorScheme)
-                : new IncognitoCustomTabColorProvider(context);
-        mHideIncognitoIconOnToolbar = isIntentFromFirstParty(intent)
-                && IntentUtils.safeGetBooleanExtra(intent, EXTRA_HIDE_INCOGNITO_ICON, false);
+        mColorProvider = new IncognitoCustomTabColorProvider(context);
         mCloseButtonIcon = TintedDrawable.constructTintedDrawable(context, R.drawable.btn_close);
         mShowShareItem = IntentUtils.safeGetBooleanExtra(
                 intent, CustomTabsIntent.EXTRA_DEFAULT_SHARE_MENU_ITEM, false);
@@ -216,12 +196,6 @@
     // incognito CCT request for all apps.
     public static boolean isValidIncognitoIntent(Intent intent) {
         if (!isIncognitoRequested(intent)) return false;
-        // Allow first parties to use for experimentation regardless of state of feature.
-        if (isIntentFromFirstParty(intent)
-                && IntentUtils.safeGetBooleanExtra(
-                        intent, EXTRA_FORCE_ENABLE_FOR_EXPERIMENT, false)) {
-            return true;
-        }
         if (!isTrustedIntent(intent)) return false;
         return CachedFeatureFlags.isEnabled(ChromeFeatureList.CCT_INCOGNITO);
     }
@@ -346,9 +320,4 @@
         }
         return list;
     }
-
-    @Override
-    public boolean shouldHideIncognitoIconOnToolbarInCct() {
-        return mHideIncognitoIconOnToolbar;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index 39b8bf9..eb9cdb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -154,8 +154,6 @@
     private CustomTabLocationBar mLocationBar;
     private LocationBarModel mLocationBarModel;
 
-    private boolean mIncognitoIconHidden;
-
     private Runnable mTitleAnimationStarter = new Runnable() {
         @Override
         public void run() {
@@ -332,15 +330,6 @@
         }
     }
 
-    /**
-     * @param value Whether the incognito icon should be hidden.
-     */
-    public void setIncognitoIconHidden(boolean value) {
-        if (mIncognitoIconHidden == value) return;
-        mIncognitoIconHidden = value;
-        requestLayout();
-    }
-
     @Override
     protected String getContentPublisher() {
         Tab tab = getToolbarDataProvider().getTab();
@@ -389,8 +378,7 @@
     }
 
     private void updateToolbarLayoutMargin() {
-        final boolean shouldShowIncognitoIcon =
-                !mIncognitoIconHidden && getToolbarDataProvider().isIncognito();
+        final boolean shouldShowIncognitoIcon = getToolbarDataProvider().isIncognito();
         mIncognitoImageView.setVisibility(shouldShowIncognitoIcon ? VISIBLE : GONE);
 
         int startMargin = calculateStartMarginWhenCloseButtonVisibilityGone();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
index 358011b..f8c9c12 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
@@ -125,8 +125,6 @@
             manager.setToolbarShadowVisibility(View.GONE);
         }
         showCustomButtonsOnToolbar();
-        CustomTabToolbar toolbar = mActivity.findViewById(R.id.toolbar);
-        toolbar.setIncognitoIconHidden(mIntentDataProvider.shouldHideIncognitoIconOnToolbarInCct());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
index edb9d992..400450e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
@@ -315,6 +315,10 @@
                 Supplier<Tab> tabProvider, Callback<Tab> printCallback,
                 @ShareOrigin int shareOrigin, boolean isSyncEnabled, long shareStartTime,
                 boolean sharingHubEnabled) {
+            Profile profile = null;
+            if (tabProvider.get() != null && tabProvider.get().getWebContents() != null) {
+                profile = Profile.fromWebContents(tabProvider.get().getWebContents());
+            }
             if (chromeShareExtras.shareDirectly()) {
                 RecordHistogram.recordEnumeratedHistogram(ANY_SHARE_HISTOGRAM_NAME,
                         ShareSourceAndroid.DIRECT_SHARE, ShareSourceAndroid.COUNT);
@@ -330,7 +334,7 @@
                 ShareSheetCoordinator coordinator = new ShareSheetCoordinator(controller,
                         lifecycleDispatcher, tabProvider,
                         new ShareSheetPropertyModelBuilder(controller,
-                                ContextUtils.getApplicationContext().getPackageManager()),
+                                ContextUtils.getApplicationContext().getPackageManager(), profile),
                         printCallback, new LargeIconBridge(Profile.getLastUsedRegularProfile()),
                         new SettingsLauncherImpl(), isSyncEnabled,
                         AppHooks.get().getImageEditorModuleProvider(),
@@ -342,7 +346,7 @@
                         "Sharing.DefaultSharesheetAndroid.Opened", shareOrigin, ShareOrigin.COUNT);
                 RecordHistogram.recordEnumeratedHistogram(ANY_SHARE_HISTOGRAM_NAME,
                         ShareSourceAndroid.ANDROID_SHARE_SHEET, ShareSourceAndroid.COUNT);
-                ShareHelper.showDefaultShareUi(params, chromeShareExtras.saveLastUsed());
+                ShareHelper.showDefaultShareUi(params, profile, chromeShareExtras.saveLastUsed());
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
index 5726b4b..b9540e19 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
@@ -27,11 +27,13 @@
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lens.LensController;
 import org.chromium.chrome.browser.lens.LensEntryPoint;
 import org.chromium.chrome.browser.lens.LensIntentParams;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.browser_ui.share.ShareParams;
 import org.chromium.components.browser_ui.share.ShareParams.TargetChosenCallback;
 import org.chromium.ui.base.WindowAndroid;
@@ -89,9 +91,10 @@
      * @param saveLastUsed True if the chosen share component should be saved for future reuse.
      */
     // TODO(crbug/1022172): Should be package-protected once modularization is complete.
-    public static void showDefaultShareUi(ShareParams params, boolean saveLastUsed) {
+    public static void showDefaultShareUi(
+            ShareParams params, @Nullable Profile profile, boolean saveLastUsed) {
         if (saveLastUsed) {
-            params.setCallback(new SaveComponentCallback(params.getCallback()));
+            params.setCallback(new SaveComponentCallback(profile, params.getCallback()));
         }
 
         ShareHelper.shareWithUi(params);
@@ -103,13 +106,13 @@
      * @param name The component name of the activity to share the image with.
      * @param imageUri The url to share with the external activity.
      */
-    public static void shareImage(
-            final WindowAndroid window, final ComponentName name, Uri imageUri) {
+    public static void shareImage(final WindowAndroid window, final Profile profile,
+            final ComponentName name, Uri imageUri) {
         Intent shareIntent = getShareImageIntent(imageUri);
         if (name == null) {
             if (TargetChosenReceiver.isSupported()) {
                 TargetChosenReceiver.sendChooserIntent(
-                        window, shareIntent, new SaveComponentCallback(null));
+                        window, shareIntent, new SaveComponentCallback(profile, null));
             } else {
                 Intent chooserIntent = Intent.createChooser(shareIntent,
                         window.getActivity().get().getString(R.string.share_link_chooser_title));
@@ -229,10 +232,13 @@
      * @param component The {@link ComponentName} of the app selected for sharing.
      */
     @VisibleForTesting
-    public static void setLastShareComponentName(ComponentName component) {
+    public static void setLastShareComponentName(Profile profile, ComponentName component) {
         SharedPreferencesManager.getInstance().writeString(
                 ChromePreferenceKeys.SHARING_LAST_SHARED_COMPONENT_NAME,
                 component.flattenToString());
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_USAGE_RANKING) && profile != null) {
+            ShareHistoryBridge.addShareEntry(profile, component.flattenToString());
+        }
     }
 
     /**
@@ -241,14 +247,17 @@
      */
     static class SaveComponentCallback implements TargetChosenCallback {
         private TargetChosenCallback mOriginalCallback;
+        private Profile mProfile;
 
-        public SaveComponentCallback(@Nullable TargetChosenCallback originalCallback) {
+        public SaveComponentCallback(
+                @Nullable Profile profile, @Nullable TargetChosenCallback originalCallback) {
             mOriginalCallback = originalCallback;
+            mProfile = profile;
         }
 
         @Override
         public void onTargetChosen(ComponentName chosenComponent) {
-            setLastShareComponentName(chosenComponent);
+            setLastShareComponentName(mProfile, chosenComponent);
             if (mOriginalCallback != null) mOriginalCallback.onTargetChosen(chosenComponent);
         }
 
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 61633ff..8490f18 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
@@ -812,16 +812,7 @@
         mLayoutStateObserver = new LayoutStateProvider.LayoutStateObserver() {
             @Override
             public void onStartedShowing(@LayoutType int layoutType, boolean showToolbar) {
-                if (layoutType == LayoutType.TAB_SWITCHER) {
-                    mLocationBarModel.setIsShowingTabSwitcher(true);
-                    mToolbar.setTabSwitcherMode(true, showToolbar, false);
-                    updateButtonStatus();
-                    if (mLocationBarModel.shouldShowLocationBarInOverviewMode()) {
-                        assert mLocationBar instanceof LocationBarCoordinator;
-                        ((LocationBarCoordinator) mLocationBar).startAutocompletePrefetch();
-                    }
-                }
-                mToolbar.setContentAttached(layoutType == LayoutType.BROWSING);
+                updateForLayout(layoutType, showToolbar, false);
             }
 
             @Override
@@ -895,6 +886,28 @@
     }
 
     /**
+     * Handle a layout change event.
+     * @param layoutType The layout being switched to.
+     * @param showToolbar Whether the toolbar should be shown.
+     * @param shouldFocusOmnibox Whether we should attempt to focus the omnibox.
+     */
+    private void updateForLayout(
+            @LayoutType int layoutType, boolean showToolbar, boolean shouldFocusOmnibox) {
+        if (layoutType == LayoutType.TAB_SWITCHER) {
+            mLocationBarModel.setIsShowingTabSwitcher(true);
+            mToolbar.setTabSwitcherMode(true, showToolbar, false);
+            updateButtonStatus();
+            if (mLocationBarModel.shouldShowLocationBarInOverviewMode()) {
+                assert mLocationBar instanceof LocationBarCoordinator;
+                ((LocationBarCoordinator) mLocationBar).startAutocompletePrefetch();
+            }
+        }
+        mToolbar.setContentAttached(layoutType == LayoutType.BROWSING);
+
+        if (shouldFocusOmnibox) maybeFocusOmnibox(layoutType, mActivityTabProvider.get());
+    }
+
+    /**
      * May set Omnibox focused if the Tab has the flag to require focusing the Omnibox.
      */
     private void maybeFocusOmnibox(@LayoutType int layout, Tab tab) {
@@ -1767,6 +1780,15 @@
 
         mLayoutStateProvider = layoutStateProvider;
         mLayoutStateProvider.addObserver(mLayoutStateObserver);
+
+        if (mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER)) {
+            // TODO(1210431): We shouldn't need to post this. Instead we should wait until the
+            //                dependencies are ready. This logic was introduced to move asynchronous
+            //                observer events from the infra (LayoutManager) into the feature using
+            //                it.
+            mControlContainer.post(() -> updateForLayout(LayoutType.TAB_SWITCHER, true, true));
+        }
+
         mAppThemeColorProvider.setLayoutStateProvider(mLayoutStateProvider);
         mLocationBarModel.setLayoutStateProvider(mLayoutStateProvider);
         if (mBottomControlsCoordinatorSupplier.get() != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
index 16779d6..1e16b7b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -29,6 +29,7 @@
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.TAB_SWITCHER_BUTTON_IS_VISIBLE;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.TRANSLATION_Y;
 
+import android.os.Handler;
 import android.view.View;
 import android.view.View.OnClickListener;
 
@@ -337,6 +338,14 @@
                 }
             }
         };
+
+        if (mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER)) {
+            new Handler().post(() -> {
+                mLayoutStateObserver.onStartedShowing(LayoutType.TAB_SWITCHER, true);
+                mLayoutStateObserver.onFinishedShowing(LayoutType.TAB_SWITCHER);
+            });
+        }
+
         mLayoutStateProvider.addObserver(mLayoutStateObserver);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
index d652d361..089eb47c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
@@ -197,7 +197,8 @@
                             mockActivity, BrowserControlsManager.ControlsPosition.TOP),
                     mActivityTestRule.getActivity().getWindowAndroid());
         });
-        ShareHelper.setLastShareComponentName(new ComponentName("test.package", "test.activity"));
+        ShareHelper.setLastShareComponentName(
+                null, new ComponentName("test.package", "test.activity"));
         // Skips the capture of screenshot and notifies with an empty file.
         ShareDelegateImpl.setScreenshotCaptureSkippedForTesting(true);
 
@@ -219,7 +220,7 @@
 
         mockActivity.waitForFileCheck();
 
-        ShareHelper.setLastShareComponentName(new ComponentName("", ""));
+        ShareHelper.setLastShareComponentName(null, new ComponentName("", ""));
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mockActivity.getActivityTab().updateAttachment(null, null);
             window.destroy();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
index c427b86e..13996b17 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -121,8 +121,6 @@
 
     private float mDpToPx;
 
-    private OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderSupplier;
-
     class LayoutObserverCallbackHelper extends CallbackHelper {
         @LayoutType
         public int layoutType;
@@ -213,13 +211,9 @@
         OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier =
                 new OneshotSupplierImpl<>();
 
-        if (mLayoutStateProviderSupplier == null) {
-            mLayoutStateProviderSupplier = new OneshotSupplierImpl<>();
-        }
-
         mManagerPhone = new LayoutManagerChromePhone(layoutManagerHost, container, mStartSurface,
                 tabContentManagerSupplier, null, overviewModeBehaviorSupplier,
-                mLayoutStateProviderSupplier, () -> mTopUiThemeColorProvider);
+                () -> mTopUiThemeColorProvider);
         verify(mStartSurfaceController)
                 .addOverviewModeObserver(mStartSurfaceOverviewModeCaptor.capture());
 
@@ -472,17 +466,10 @@
             performToolbarSideSwipe(ScrollDirection.RIGHT);
             Assert.assertEquals(
                     LayoutType.TOOLBAR_SWIPE, mManager.getActiveLayout().getLayoutType());
-            Assert.assertTrue(
-                    mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.TOOLBAR_SWIPE));
+            Assert.assertTrue(mManager.isLayoutVisible(LayoutType.TOOLBAR_SWIPE));
         });
 
-        // The |startedShowingCallback| callCount 0 is reserved for the default layout during
-        // initialization. Because LayoutManager does not explicitly hide the old layout when a new
-        // layout is forced to show, the callCount for |finishedShowingCallback|,
-        // |startedHidingCallback|, and |finishedHidingCallback| are still 0.
-        // TODO(crbug.com/1108496): update the callCount when LayoutManager explicitly hide the old
-        // layout.
-        startedShowingCallback.waitForCallback(1);
+        startedShowingCallback.waitForCallback(0);
         Assert.assertEquals(LayoutType.TOOLBAR_SWIPE, startedShowingCallback.layoutType);
 
         finishedShowingCallback.waitForCallback(0);
@@ -491,8 +478,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             finishToolbarSideSwipe();
             Assert.assertEquals(LayoutType.BROWSING, mManager.getActiveLayout().getLayoutType());
-            Assert.assertTrue(
-                    mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.BROWSING));
+            Assert.assertTrue(mManager.isLayoutVisible(LayoutType.BROWSING));
         });
 
         startedHidingCallback.waitForCallback(0);
@@ -501,7 +487,7 @@
         finishedHidingCallback.waitForCallback(0);
         Assert.assertEquals(LayoutType.TOOLBAR_SWIPE, finishedHidingCallback.layoutType);
 
-        startedShowingCallback.waitForCallback(2);
+        startedShowingCallback.waitForCallback(1);
         Assert.assertEquals(LayoutType.BROWSING, startedShowingCallback.layoutType);
 
         finishedShowingCallback.waitForCallback(1);
@@ -529,8 +515,7 @@
                     "layoutManager is way too long to end motion", simulateTime(mManager, 1000));
             Assert.assertEquals(
                     LayoutType.TAB_SWITCHER, mManager.getActiveLayout().getLayoutType());
-            Assert.assertTrue(
-                    mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.TAB_SWITCHER));
+            Assert.assertTrue(mManager.isLayoutVisible(LayoutType.TAB_SWITCHER));
         });
 
         // The |startedShowingCallback| callCount 0 is reserved for the default layout during
@@ -550,8 +535,7 @@
             Assert.assertTrue(
                     "layoutManager is way too long to end motion", simulateTime(mManager, 1000));
 
-            Assert.assertTrue(
-                    mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.BROWSING));
+            Assert.assertTrue(mManager.isLayoutVisible(LayoutType.BROWSING));
         });
 
         startedHidingCallback.waitForCallback(0);
@@ -589,17 +573,10 @@
             Assert.assertThat("Incorrect active LayoutType",
                     mManager.getActiveLayout().getLayoutType(), is(LayoutType.SIMPLE_ANIMATION));
             Assert.assertThat("Incorrect active Layout",
-                    mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.SIMPLE_ANIMATION),
-                    is(true));
+                    mManager.isLayoutVisible(LayoutType.SIMPLE_ANIMATION), is(true));
         });
 
-        // The |startedShowingCallback| callCount 0 is reserved for the default layout during
-        // initialization. Because LayoutManager does not explicitly hide the old layout when a new
-        // layout is forced to show, the callCount for |finishedShowingCallback|,
-        // |startedHidingCallback|, and |finishedHidingCallback| are still 0.
-        // TODO(crbug.com/1108496): update the callCount when LayoutManager explicitly hide the old
-        // layout.
-        startedShowingCallback.waitForCallback(1);
+        startedShowingCallback.waitForCallback(0);
         Assert.assertThat("startedShowingCallback with incorrect LayoutType",
                 startedShowingCallback.layoutType, is(LayoutType.SIMPLE_ANIMATION));
 
@@ -626,7 +603,7 @@
         Assert.assertThat("finishedHidingCallback with incorrectLayoutType",
                 finishedHidingCallback.layoutType, is(LayoutType.SIMPLE_ANIMATION));
 
-        startedShowingCallback.waitForCallback(2);
+        startedShowingCallback.waitForCallback(1);
         Assert.assertThat("startedShowingCallback with incorrectLayoutType",
                 startedShowingCallback.layoutType, is(LayoutType.BROWSING));
 
@@ -641,46 +618,46 @@
             LayoutObserverCallbackHelper startedHidingCallback,
             LayoutObserverCallbackHelper finishedHidingCallback) throws TimeoutException {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mLayoutStateProviderSupplier = new OneshotSupplierImpl<>();
+            initializeLayoutManagerPhone(2, 0);
+            mManager.addObserver(new LayoutStateProvider.LayoutStateObserver() {
+                @Override
+                public void onStartedShowing(int layoutType, boolean showToolbar) {
+                    Log.d(TAG, "Started to show: " + layoutType);
+                    startedShowingCallback.layoutType = layoutType;
+                    startedShowingCallback.notifyCalled();
+                }
 
-            mLayoutStateProviderSupplier.onAvailable((layoutStateProvider) -> {
-                layoutStateProvider.addObserver(new LayoutStateProvider.LayoutStateObserver() {
-                    @Override
-                    public void onStartedShowing(int layoutType, boolean showToolbar) {
-                        Log.d(TAG, "Started to show: " + layoutType);
-                        startedShowingCallback.layoutType = layoutType;
-                        startedShowingCallback.notifyCalled();
-                    }
+                @Override
+                public void onFinishedShowing(int layoutType) {
+                    Log.d(TAG, "finished to show: " + layoutType);
+                    finishedShowingCallback.layoutType = layoutType;
+                    finishedShowingCallback.notifyCalled();
+                }
 
-                    @Override
-                    public void onFinishedShowing(int layoutType) {
-                        Log.d(TAG, "finished to show: " + layoutType);
-                        finishedShowingCallback.layoutType = layoutType;
-                        finishedShowingCallback.notifyCalled();
-                    }
+                @Override
+                public void onStartedHiding(
+                        int layoutType, boolean showToolbar, boolean delayAnimation) {
+                    Log.d(TAG, "Started to hide: " + layoutType);
+                    startedHidingCallback.layoutType = layoutType;
+                    startedHidingCallback.notifyCalled();
+                }
 
-                    @Override
-                    public void onStartedHiding(
-                            int layoutType, boolean showToolbar, boolean delayAnimation) {
-                        Log.d(TAG, "Started to hide: " + layoutType);
-                        startedHidingCallback.layoutType = layoutType;
-                        startedHidingCallback.notifyCalled();
-                    }
-
-                    @Override
-                    public void onFinishedHiding(int layoutType) {
-                        Log.d(TAG, "finished to hide: " + layoutType);
-                        finishedHidingCallback.layoutType = layoutType;
-                        finishedHidingCallback.notifyCalled();
-                    }
-                });
+                @Override
+                public void onFinishedHiding(int layoutType) {
+                    Log.d(TAG, "finished to hide: " + layoutType);
+                    finishedHidingCallback.layoutType = layoutType;
+                    finishedHidingCallback.notifyCalled();
+                }
             });
 
-            initializeLayoutManagerPhone(2, 0);
             Assert.assertEquals(LayoutType.BROWSING, mManager.getActiveLayout().getLayoutType());
         });
 
-        startedShowingCallback.waitForCallback(0);
+        if (mManager.isLayoutVisible(LayoutType.BROWSING)) {
+            startedShowingCallback.layoutType = LayoutType.BROWSING;
+        } else {
+            startedShowingCallback.waitForCallback(0);
+        }
         Assert.assertEquals(LayoutType.BROWSING, startedShowingCallback.layoutType);
     }
 
@@ -692,19 +669,15 @@
         CallbackHelper tabSelectionHintedCallback = new CallbackHelper();
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mLayoutStateProviderSupplier = new OneshotSupplierImpl<>();
-
-            mLayoutStateProviderSupplier.onAvailable((layoutStateProvider) -> {
-                layoutStateProvider.addObserver(new LayoutStateProvider.LayoutStateObserver() {
-                    @Override
-                    public void onTabSelectionHinted(int tabId) {
-                        Log.d(TAG, "onTabSelectionHinted");
-                        tabSelectionHintedCallback.notifyCalled();
-                    }
-                });
+            initializeLayoutManagerPhone(2, 0);
+            mManager.addObserver(new LayoutStateProvider.LayoutStateObserver() {
+                @Override
+                public void onTabSelectionHinted(int tabId) {
+                    Log.d(TAG, "onTabSelectionHinted");
+                    tabSelectionHintedCallback.notifyCalled();
+                }
             });
 
-            initializeLayoutManagerPhone(2, 0);
             mManager.showOverview(true);
 
             Assert.assertTrue(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
index 605927548..260ab27 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
@@ -16,7 +16,6 @@
 import static org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule.LONG_TIMEOUT_MS;
 import static org.chromium.chrome.browser.customtabs.CustomTabsTestUtils.addActionButtonToIntent;
 import static org.chromium.chrome.browser.customtabs.CustomTabsTestUtils.createTestBitmap;
-import static org.chromium.chrome.browser.customtabs.IncognitoCustomTabIntentDataProvider.EXTRA_FORCE_ENABLE_FOR_EXPERIMENT;
 
 import android.annotation.TargetApi;
 import android.app.NotificationManager;
@@ -261,41 +260,6 @@
 
     @Test
     @MediumTest
-    @Features.DisableFeatures({ChromeFeatureList.CCT_INCOGNITO})
-    public void canLaunchFirstPartyIncognitoWithExtraWhenDisabled() throws Exception {
-        Intent intent = createMinimalIncognitoCustomTabIntent();
-        intent.putExtra(EXTRA_FORCE_ENABLE_FOR_EXPERIMENT, true);
-        CustomTabActivity activity = launchIncognitoCustomTab(intent);
-        assertTrue(activity.getActivityTab().isIncognito());
-        assertProfileUsedIsNonPrimary();
-    }
-
-    @Test
-    @MediumTest
-    @Features.EnableFeatures({ChromeFeatureList.CCT_INCOGNITO})
-    public void canHideToolbarIncognitoLogo() throws Exception {
-        Intent intent = createMinimalIncognitoCustomTabIntent();
-        // The icon is only hidden if an extra is supplied.
-        intent.putExtra(IncognitoCustomTabIntentDataProvider.EXTRA_HIDE_INCOGNITO_ICON, true);
-        launchIncognitoCustomTab(intent);
-        Espresso.onView(withId(R.id.incognito_cct_logo_image_view))
-                .check(matches(not(isDisplayed())));
-    }
-
-    @Test
-    @MediumTest
-    @Features.EnableFeatures({ChromeFeatureList.CCT_INCOGNITO})
-    public void canCustomizeToolbarColor() throws Exception {
-        Intent intent = createMinimalIncognitoCustomTabIntent();
-        // The color is only allowed if an extra is supplied.
-        intent.putExtra(IncognitoCustomTabIntentDataProvider.EXTRA_USE_NORMAL_PROFILE_STYLE, true);
-        intent.putExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, Color.RED);
-        CustomTabActivity activity = launchIncognitoCustomTab(intent);
-        assertEquals(Color.RED, getToolbarColor(activity));
-    }
-
-    @Test
-    @MediumTest
     @Features.EnableFeatures({ChromeFeatureList.CCT_INCOGNITO})
     public void ignoresCustomizedToolbarColor() throws Exception {
         Intent intent = createMinimalIncognitoCustomTabIntent();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
index 054ce6468..0654131 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
@@ -297,7 +297,7 @@
                 mActivityTestRule.getActivity().getLayoutManager().hideOverview(false);
             }
         });
-        LayoutTestUtils.waitForLayout(
-                mActivityTestRule.getActivity().getLayoutManager(), LayoutType.TAB_SWITCHER);
+        LayoutTestUtils.waitForLayout(mActivityTestRule.getActivity().getLayoutManager(),
+                inSwitcher ? LayoutType.TAB_SWITCHER : LayoutType.BROWSING);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
index d233903..596d6d8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
@@ -653,7 +653,8 @@
             }
         });
 
-        LayoutTestUtils.waitForLayout(mActivity.getLayoutManager(), LayoutType.TAB_SWITCHER);
+        LayoutTestUtils.waitForLayout(mActivity.getLayoutManager(),
+                shown ? LayoutType.TAB_SWITCHER : LayoutType.BROWSING);
         ThreadUtils.runOnUiThreadBlocking(mTestSupport::endAllAnimations);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java
index 95bd9bec..89b2127 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java
@@ -5,8 +5,6 @@
 package org.chromium.chrome.browser.compositor.layouts;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -23,11 +21,9 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.layouts.SceneOverlay;
 import org.chromium.chrome.browser.theme.TopUiThemeColorProvider;
 import org.chromium.chrome.browser.toolbar.bottom.ScrollingBottomViewSceneLayer;
@@ -59,9 +55,6 @@
     private ObservableSupplier<TabContentManager> mTabContentManagerSupplier;
 
     @Mock
-    private OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderOneshotSupplier;
-
-    @Mock
     private TopUiThemeColorProvider mTopUiThemeColorProvider;
 
     private LayoutManagerImpl mLayoutManager;
@@ -73,11 +66,9 @@
         when(mLayoutManagerHost.getContext()).thenReturn(mContext);
         when(mContext.getResources()).thenReturn(mResources);
         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
-        doNothing().when(mLayoutStateProviderOneshotSupplier).set(any());
 
         mLayoutManager = new LayoutManagerImpl(mLayoutManagerHost, mContainerView,
-                mTabContentManagerSupplier, null, mLayoutStateProviderOneshotSupplier,
-                () -> mTopUiThemeColorProvider);
+                mTabContentManagerSupplier, null, () -> mTopUiThemeColorProvider);
     }
 
     @Test
diff --git a/chrome/android/modules/chrome_bundle_tmpl.gni b/chrome/android/modules/chrome_bundle_tmpl.gni
index 8ffac28..18233436 100644
--- a/chrome/android/modules/chrome_bundle_tmpl.gni
+++ b/chrome/android/modules/chrome_bundle_tmpl.gni
@@ -164,7 +164,7 @@
     proguard_enabled = !is_java_debug
     enable_language_splits = true
     extra_modules = _extra_modules
-    system_image_locale_allowlist = android_apk_locales
+    system_image_locale_allowlist = locales - android_bundle_only_locales
     is_multi_abi = _is_multi_abi
     validate_services = _enable_chrome_module
 
diff --git a/chrome/android/monochrome/scripts/monochrome_apk_checker_test.py b/chrome/android/monochrome/scripts/monochrome_apk_checker_test.py
index fde75ff..0276911 100644
--- a/chrome/android/monochrome/scripts/monochrome_apk_checker_test.py
+++ b/chrome/android/monochrome/scripts/monochrome_apk_checker_test.py
@@ -60,50 +60,7 @@
     r'assets/unwind_cfi_32', # Generated from apk's shared library
      # All pak files except chrome_100_percent.pak are different
     r'assets/resources\.pak',
-    r'assets/locales/am\.pak',
-    r'assets/locales/ar\.pak',
-    r'assets/locales/bg\.pak',
-    r'assets/locales/ca\.pak',
-    r'assets/locales/cs\.pak',
-    r'assets/locales/da\.pak',
-    r'assets/locales/de\.pak',
-    r'assets/locales/el\.pak',
-    r'assets/locales/en-GB\.pak',
-    r'assets/locales/en-US\.pak',
-    r'assets/locales/es-419\.pak',
-    r'assets/locales/es\.pak',
-    r'assets/locales/fa\.pak',
-    r'assets/locales/fi\.pak',
-    r'assets/locales/fil\.pak',
-    r'assets/locales/fr\.pak',
-    r'assets/locales/he\.pak',
-    r'assets/locales/hi\.pak',
-    r'assets/locales/hr\.pak',
-    r'assets/locales/hu\.pak',
-    r'assets/locales/id\.pak',
-    r'assets/locales/it\.pak',
-    r'assets/locales/ja\.pak',
-    r'assets/locales/ko\.pak',
-    r'assets/locales/lt\.pak',
-    r'assets/locales/lv\.pak',
-    r'assets/locales/nb\.pak',
-    r'assets/locales/nl\.pak',
-    r'assets/locales/pl\.pak',
-    r'assets/locales/pt-BR\.pak',
-    r'assets/locales/pt-PT\.pak',
-    r'assets/locales/ro\.pak',
-    r'assets/locales/ru\.pak',
-    r'assets/locales/sk\.pak',
-    r'assets/locales/sl\.pak',
-    r'assets/locales/sr\.pak',
-    r'assets/locales/sv\.pak',
-    r'assets/locales/sw\.pak',
-    r'assets/locales/th\.pak',
-    r'assets/locales/tr\.pak',
-    r'assets/locales/uk\.pak',
-    r'assets/locales/vi\.pak',
-    r'assets/locales/zh-CN\.pak',
-    r'assets/locales/zh-TW\.pak')
+    r'assets/locales/.*\.pak')
 
 # The files in WebView are not same as those in Monochrome
 WEBVIEW_CHANGES = BuildFileMatchRegex(
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 7818578..cd8dd25f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5954,6 +5954,12 @@
       <message name="IDS_TOOLTIP_EXTENSIONS_BUTTON" desc="The tooltip for the extensions button">
         Extensions
       </message>
+      <message name="IDS_TOOLTIP_SIDE_PANEL_SHOW" desc="The tooltip for the side panel button, when closed">
+        Show side panel
+      </message>
+      <message name="IDS_TOOLTIP_SIDE_PANEL_HIDE" desc="The tooltip for the side panel button, when open">
+        Hide side panel
+      </message>
       <if expr="is_macosx">
         <message name="IDS_TOOLTIP_CLOSE_TAB" desc="The tooltip for the close tab button">
           Close
diff --git a/chrome/app/generated_resources_grd/IDS_TOOLTIP_SIDE_PANEL_HIDE.png.sha1 b/chrome/app/generated_resources_grd/IDS_TOOLTIP_SIDE_PANEL_HIDE.png.sha1
new file mode 100644
index 0000000..dbf8476a
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_TOOLTIP_SIDE_PANEL_HIDE.png.sha1
@@ -0,0 +1 @@
+f00bb2293aca685a98903533a0caa033f1d64175
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TOOLTIP_SIDE_PANEL_SHOW.png.sha1 b/chrome/app/generated_resources_grd/IDS_TOOLTIP_SIDE_PANEL_SHOW.png.sha1
new file mode 100644
index 0000000..a0f72f3
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_TOOLTIP_SIDE_PANEL_SHOW.png.sha1
@@ -0,0 +1 @@
+82196a1826a2711cfa6774c3fe0e782554f1115e
\ No newline at end of file
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index f32374af..6bd1e0b 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -857,7 +857,7 @@
 <translation id="1885106732301550621">Espacio en disco</translation>
 <translation id="1886996562706621347">Permitir que los sitios se conviertan en controladores de protocolos predeterminados (recomendado)</translation>
 <translation id="1887442540531652736">No se ha podido iniciar sesión</translation>
-<translation id="1887597546629269384">Di "Ok Google" otra vez</translation>
+<translation id="1887597546629269384">Di "Hey Google" otra vez</translation>
 <translation id="1890674179660343635">&lt;span&gt;ID: &lt;/span&gt;<ph name="EXTENSION_ID" /></translation>
 <translation id="1891362123137972260">Queda muy poco espacio en el disco. Libera espacio ahora.</translation>
 <translation id="189210018541388520">Abrir en pantalla completa</translation>
@@ -3276,7 +3276,7 @@
 <translation id="4531924570968473143">¿A quién quieres añadir a este <ph name="DEVICE_TYPE" />?</translation>
 <translation id="4532625150642446981">"<ph name="USB_DEVICE_NAME" />" está en uso. Si el dispositivo se reasigna mientras se está usando, podrían producirse errores. ¿Seguro que quieres continuar?</translation>
 <translation id="4532646538815530781">Este sitio web está usando sensores de movimiento.</translation>
-<translation id="4533846798469727141">Ahora di "Ok Google"</translation>
+<translation id="4533846798469727141">Ahora di "Hey Google"</translation>
 <translation id="4533985347672295764">Tiempo de uso de la CPU</translation>
 <translation id="4534661889221639075">Inténtalo de nuevo.</translation>
 <translation id="4535127706710932914">Perfil predeterminado</translation>
diff --git a/chrome/app/resources/generated_resources_ky.xtb b/chrome/app/resources/generated_resources_ky.xtb
index a01e52a..5e0050f 100644
--- a/chrome/app/resources/generated_resources_ky.xtb
+++ b/chrome/app/resources/generated_resources_ky.xtb
@@ -1853,7 +1853,7 @@
 <translation id="2942279350258725020">Android жазышуулары</translation>
 <translation id="2942560570858569904">Күтүп жатат…</translation>
 <translation id="2942581856830209953">Бул баракты ыңгайлаштыруу</translation>
-<translation id="2944060181911631861">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Google'га мүчүлүштүктөрдү аныктоо жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө жөнөтүп, Android'де иштөө тажрыйбаңызды жакшыртууга жардам бериңиз. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул дайындар Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK1" />Кеңири маалымат<ph name="END_LINK1" /></translation>
+<translation id="2944060181911631861">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Google'га мүчүлүштүктөрдү аныктоо жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө жөнөтүп, Android'де иштөө тажрыйбаңызды жакшыртууга жардам бериңиз. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул нерселер Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK1" />Кеңири маалымат<ph name="END_LINK1" /></translation>
 <translation id="2946119680249604491">Туташуу кошуу</translation>
 <translation id="2946640296642327832">Bluetooth иштетүү</translation>
 <translation id="2947605845283690091">Веб серепчи тез болушу керек. Бир аз убакыт бөлүп, <ph name="BEGIN_LINK" />кеңейтүүлөрдү текшериңиз<ph name="END_LINK" />.</translation>
@@ -2328,7 +2328,7 @@
 <translation id="3473479545200714844">Экран чоңойткуч</translation>
 <translation id="3474218480460386727">Жаңы сөздөр үчүн 99 же андан аз тамгаларды колдонуңуз</translation>
 <translation id="3475843873335999118">Кечиресиз, манжа изиңиз дагы эле тааныла элек. Сырсөзүңүздү киргизиңиз.</translation>
-<translation id="3476303763173086583">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Балаңыздын Android'ди колдонуу тажрыйбасын жакшыртууга көмөктөшүп, мүчүлүштүктөрдү издөө жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө Google'га жөнөтүүгө уруксат бериңиз. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Түзмөктүн ээси бул түзмөктөн мүчүлүштүктөрдү аныктоо жана колдонуу дайындарын Google'га жөнөтүү мүмкүнчүлүгүн иштетиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул дайындар анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
+<translation id="3476303763173086583">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Балаңыздын Android'ди колдонуу тажрыйбасын жакшыртууга көмөктөшүп, мүчүлүштүктөрдү издөө жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө Google'га жөнөтүүгө уруксат бериңиз. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Түзмөктүн ээси бул түзмөктөн мүчүлүштүктөрдү аныктоо жана колдонуу дайындарын Google'га жөнөтүү мүмкүнчүлүгүн иштетиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул нерселер анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
 <translation id="347670947055184738">Ой!  Тутум бул түзмөк үчүн саясатты ала албай калды.</translation>
 <translation id="347785443197175480"><ph name="HOST" /> камераңыз менен микрофонуңузду колдоно берсин</translation>
 <translation id="3479552764303398839">Азыр эмес</translation>
@@ -3013,7 +3013,7 @@
 <translation id="4209464433672152343">Басып чыгаруу үчүн документтер <ph name="BEGIN_LINK_HELP" />Google'га жөнөтүлөт<ph name="END_LINK_HELP" />. <ph name="BEGIN_LINK_DASHBOARD" />Google'дун виртуалдык принтеринин куралдар тактасынан<ph name="END_LINK_DASHBOARD" /> принтерлерди жана принтерлердин басып чыгаруу таржымалын көрүп, түзөтүп, башкарыңыз.</translation>
 <translation id="4210048056321123003">Виртуалдык машина жүктөлүп алынууда</translation>
 <translation id="421182450098841253">Кыстармалар тилкесин &amp;көрсөтүү</translation>
-<translation id="4211851069413100178">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Google'га мүчүлүштүктөрдү аныктоо жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө жөнөтүп, Android'де иштөө тажрыйбаңызды жакшыртууга жардам бериңиз. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Түзмөктүн ээси бул түзмөктөн мүчүлүштүктөрдү аныктоо жана колдонуу дайындарын Google'га жөнөтүү мүмкүнчүлүгүн иштетиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул дайындар Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
+<translation id="4211851069413100178">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Google'га мүчүлүштүктөрдү аныктоо жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө жөнөтүп, Android'де иштөө тажрыйбаңызды жакшыртууга жардам бериңиз. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Түзмөктүн ээси бул түзмөктөн мүчүлүштүктөрдү аныктоо жана колдонуу дайындарын Google'га жөнөтүү мүмкүнчүлүгүн иштетиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул нерселер Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
 <translation id="42126664696688958">Экспорттоо</translation>
 <translation id="42137655013211669">Бул булакка кирүүгө сервер тыюу салган.</translation>
 <translation id="4217571870635786043">Үн менен жазуу</translation>
@@ -4230,7 +4230,7 @@
 <translation id="5584915726528712820"><ph name="BEGIN_PARAGRAPH1" />Түзмөгүңүздүн иштеши, тактап айтканда, батареянын кубаты, колдонмолордун пайдаланылышы жана Интернет байланышынын сапаты тууралуу маалымат алып турабыз. Дайындар Google'дун кызматтарын жакшыртуу үчүн колдонулат. Топтолгон маалыматтын айрымдарын Android иштеп чыгуучулары өз кызматтарын өркүндөтүү үчүн колдонушу мүмкүн.<ph name="END_PARAGRAPH1" />
     <ph name="BEGIN_PARAGRAPH2" />Бул функциянын өчүрүлүшү түзмөктүн тутумунун жаңыртылышына жана коопсуздугуна таасирин тийгизбейт.<ph name="END_PARAGRAPH2" />
     <ph name="BEGIN_PARAGRAPH3" />Түзмөктүн ээси бул функцияны Жөндөөлөр &gt; Өркүндөтүлгөн жөндөөлөр &gt; Мүчүлүштүктөрдү аныктоо жана колдонуу дайындарын автоматтык түрдө Google'га жөнөтүү аркылуу көзөмөлдөй алат.<ph name="END_PARAGRAPH3" />
-    <ph name="BEGIN_PARAGRAPH4" />Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул дайындар Google аккаунтуңузга сакталышы мүмкүн. Төмөнкү шилтеме менен өтүп, дайын-даректериңизди көрүп, өчүрүп жана аккаунтуңуздун жөндөөлөрүн өзгөртө аласыз: account.google.com.<ph name="END_PARAGRAPH4" /></translation>
+    <ph name="BEGIN_PARAGRAPH4" />Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул нерселер Google аккаунтуңузга сакталышы мүмкүн. Төмөнкү шилтеме менен өтүп, дайын-даректериңизди көрүп, өчүрүп жана аккаунтуңуздун жөндөөлөрүн өзгөртө аласыз: account.google.com.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="5585019845078534178">Карточкалар</translation>
 <translation id="5585118885427931890">Кыстармалар куржуну түзүлгөн жок.</translation>
 <translation id="558563010977877295">Белгилүү бир баракты же барактар топтомун ачуу</translation>
@@ -5255,7 +5255,7 @@
 <translation id="6725073593266469338">Интерфейс кызматы</translation>
 <translation id="6725206449694821596">Internet Printing Protocol (IPP)</translation>
 <translation id="672609503628871915">Эмне жаңылык бар</translation>
-<translation id="67269783048918309">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул дайындар анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
+<translation id="67269783048918309">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул нерселер анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
 <translation id="6727969043791803658">Туташып турат, батареянын деңгээли – <ph name="BATTERY_PERCENTAGE" />%</translation>
 <translation id="6732087373923685049">камера</translation>
 <translation id="6732801395666424405">Тастыктамалар жүктөлгөн жок</translation>
@@ -6699,7 +6699,7 @@
 <translation id="8267961145111171918"><ph name="BEGIN_PARAGRAPH1" />Түзмөгүңүздүн иштеши, тактап айтканда, батареянын кубаты, колдонмолордун пайдаланылышы жана Интернет байланышынын сапаты тууралуу маалымат алып турабыз. Дайындар Google'дун кызматтарын жакшыртуу үчүн колдонулат. Топтолгон маалыматтын айрымдарын Android иштеп чыгуучулары өз кызматтарын өркүндөтүү үчүн колдонушу мүмкүн.<ph name="END_PARAGRAPH1" />
     <ph name="BEGIN_PARAGRAPH2" />Бул функциянын өчүрүлүшү түзмөктүн тутумунун жаңыртылышына жана коопсуздугуна таасирин тийгизбейт.<ph name="END_PARAGRAPH2" />
     <ph name="BEGIN_PARAGRAPH3" />Түзмөктүн ээси бул функцияны Жөндөөлөр &gt; Өркүндөтүлгөн жөндөөлөр &gt; Мүчүлүштүктөрдү аныктоо жана колдонуу дайындарын автоматтык түрдө Google'га жөнөтүү аркылуу көзөмөлдөй алат.<ph name="END_PARAGRAPH3" />
-    <ph name="BEGIN_PARAGRAPH4" />Эгер балаңыздын түзмөгүндө кошумча Колдонмолор жана Интернеттеги аракеттердин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул дайындар балаңыздын Google аккаунтунда сакталышы мүмкүн. Төмөнкү шилтеме менен өтүп, дайындарды көрүп, өчүрүп жана аккаунттун жөндөөлөрүн өзгөртө аласыз: account.google.com.<ph name="END_PARAGRAPH4" /></translation>
+    <ph name="BEGIN_PARAGRAPH4" />Эгер балаңыздын түзмөгүндө кошумча Колдонмолор жана Интернеттеги аракеттердин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул нерселер балаңыздын Google аккаунтунда сакталышы мүмкүн. Төмөнкү шилтеме менен өтүп, дайындарды көрүп, өчүрүп жана аккаунттун жөндөөлөрүн өзгөртө аласыз: account.google.com.<ph name="END_PARAGRAPH4" /></translation>
 <translation id="826905130698769948">Кардардын сертификаты жараксыз</translation>
 <translation id="8270242299912238708">PDF документтери</translation>
 <translation id="827097179112817503">Башкы бет баскычын көрсөтүү</translation>
@@ -6957,7 +6957,7 @@
 <translation id="8591783563402255548">1 секунд</translation>
 <translation id="8592141010104017453">Билдирмелер такыр көрүнбөсүн</translation>
 <translation id="859246725979739260">Бул сайттын жайгашкан жериңизди көрүү мүмкүнчүлүгү бөгөттөлгөн</translation>
-<translation id="8593121833493516339">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Балаңыздын Android'ди колдонуу тажрыйбасын жакшыртууга көмөктөшүп, мүчүлүштүктөрдү издөө жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө Google'га жөнөтүүгө уруксат бериңиз. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул дайындар анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK1" />Кеңири маалымат<ph name="END_LINK1" /></translation>
+<translation id="8593121833493516339">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Балаңыздын Android'ди колдонуу тажрыйбасын жакшыртууга көмөктөшүп, мүчүлүштүктөрдү издөө жана түзмөк менен колдонмолорду пайдалануу дайындарын автоматтык түрдө Google'га жөнөтүүгө уруксат бериңиз. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул нерселер анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK1" />Кеңири маалымат<ph name="END_LINK1" /></translation>
 <translation id="8594908476761052472">Видео жаздыруу</translation>
 <translation id="8596540852772265699">Өзгөчөлөштүрүлгөн файлдар</translation>
 <translation id="8597845839771543242">Менчик форматы:</translation>
@@ -7082,7 +7082,7 @@
 <translation id="8719653885894320876"><ph name="PLUGIN_NAME" /> жүктөлүп алынбай калды</translation>
 <translation id="8720200012906404956">Мобилдик тармак изделүүдө. <ph name="BEGIN_LINK" />Кеңири маалымат<ph name="END_LINK" /></translation>
 <translation id="8720816553731218127">Орнотуу убактысынын аттрибуттары үчүн берилген ишке кошуу убакыты аяктады.</translation>
-<translation id="8722912030556880711">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул дайындар Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
+<translation id="8722912030556880711">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул нерселер Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
 <translation id="8724405322205516354">Бул сүрөтчө көрүнгөндө, манжаңыздын изи менен өздүгүңүздү же кандайдыр бир нерсени сатып алууну ырастайсыз.</translation>
 <translation id="8724409975248965964">Манжа изи кошулду</translation>
 <translation id="8724859055372736596">Куржунда &amp;көрсөтүү</translation>
@@ -7528,7 +7528,7 @@
 <translation id="917350715406657904">Ата-энең <ph name="APP_NAME" /> колдонмосуна койгон чекке жеттиң. Аны эртең <ph name="TIME_LIMIT" /> колдоно аласың.</translation>
 <translation id="9174401638287877180">Колдонуу жана мүчүлүштүктөрдү аныктоо маалыматын жөнөтүү. Балаңыздын Android'ди колдонуу тажрыйбасын жакшыртууга көмөктөшүп, мүчүлүштүктөрдү издөө жана түзмөк менен колдонмолорду пайдалануу маалыматын автоматтык түрдө Google'га жөнөтүүгө уруксат бериңиз. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым маалыматтар тобу Google колдонмолоруна жана Android'дин иштеп чыгуучулары сыяктуу өнөктөштөрүнө да жардам берет. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул маалымат анын Google аккаунтуна сакталышы мүмкүн.</translation>
 <translation id="917510707618656279">Сайт Bluetooth түзмөктөрүн колдонгону жатканда уруксат сурайт</translation>
-<translation id="9176476835295860688">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул дайындар Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
+<translation id="9176476835295860688">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Бул <ph name="BEGIN_LINK1" />жөндөөнү<ph name="END_LINK1" /> түзмөктүн ээси иштетет. Эгер кошумча Колдонмолор жана Интернеттеги аракеттериңиздин таржымалынын жөндөөлөрү күйгүзүлгөн болсо, бул нерселер Google аккаунтуңузга сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
 <translation id="9176611096776448349"><ph name="WINDOW_TITLE" /> – Bluetooth түзмөгү туташты</translation>
 <translation id="9179524979050048593">Кирүү экранындагы колдонуучу аты</translation>
 <translation id="9180281769944411366">Бул бир нече мүнөткө созулушу мүмкүн. Linux контейнери иштетилип баштады.</translation>
@@ -7536,7 +7536,7 @@
 <translation id="9182556968660520230">Сайттар корголгон мазмунду ойното албасын</translation>
 <translation id="918352324374649435">{COUNT,plural, =1{Колдонмо}other{# колдонмо}}</translation>
 <translation id="9186963452600581158">Баланын Google аккаунту менен кирүү</translation>
-<translation id="9188732951356337132">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул дайындар анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
+<translation id="9188732951356337132">Колдонуу жана мүчүлүштүктөрдү аныктоо дайындарын жөнөтүү. Учурда бул түзмөк мүчүлүштүктөрдү аныктоо маалыматын, түзмөктүн жана колдонмонун иштетилиши жөнүндө дайындарды Google'га автоматтык түрдө жөнөтүп жатат. Бул маалымат балаңыздын өздүгүн аныктоо үчүн колдонулбайт жана тутум менен колдонмонун кыйла туруктуу иштешин камсыз кылууга жана башка нерселерди жакшыртууга көмөктөшөт. Айрым дайын-даректердин Google'дун өнөктөштөрүнө, мисалы, Android'ди иштеп чыгуучуларга да кереги тийиши мүмкүн. Эгер кошумча Колдонмолор жана Интернеттеги аракеттер таржымалы балаңыз үчүн күйгүзүлгөн болсо, бул нерселер анын Google аккаунтуна сакталышы мүмкүн. <ph name="BEGIN_LINK2" />Кеңири маалымат<ph name="END_LINK2" /></translation>
 <translation id="9198090666959937775">Android телефонуңузду коопсуздук ачкычы катары колдонуңуз</translation>
 <translation id="920045321358709304"><ph name="SEARCH_ENGINE" /> аркылуу издөө</translation>
 <translation id="9201023452444595544">Баардык оффлайн маалыматы тазаланат</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e4645c8..8d9c15e1 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2379,9 +2379,6 @@
     deps += [
       "//ash/components/audio",
       "//ash/constants",
-      "//ash/content/help_app_ui",
-      "//ash/content/help_app_ui:mojo_bindings",
-      "//ash/content/help_app_ui/search:mojo_bindings",
       "//ash/content/scanning",
       "//ash/content/scanning/mojom",
       "//chrome/app/theme:chrome_unscaled_resources_grit",
@@ -2403,6 +2400,9 @@
       "//chromeos/components/diagnostics_ui/mojom",
       "//chromeos/components/eche_app_ui",
       "//chromeos/components/eche_app_ui/mojom",
+      "//chromeos/components/help_app_ui",
+      "//chromeos/components/help_app_ui:mojo_bindings",
+      "//chromeos/components/help_app_ui/search:mojo_bindings",
       "//chromeos/components/local_search_service",
       "//chromeos/components/local_search_service/public/cpp:cpp",
       "//chromeos/components/local_search_service/public/mojom",
@@ -3408,6 +3408,8 @@
       "accessibility/live_caption_controller_factory.h",
       "accessibility/live_caption_speech_recognition_host.cc",
       "accessibility/live_caption_speech_recognition_host.h",
+      "accuracy_tips/accuracy_service_factory.cc",
+      "accuracy_tips/accuracy_service_factory.h",
       "apps/app_service/app_icon_factory.cc",
       "apps/app_service/app_icon_factory.h",
       "apps/app_service/app_icon_source.cc",
@@ -4240,6 +4242,7 @@
       "//chrome/common/search:generate_colors_info",
       "//chrome/common/themes:autogenerated_theme_util",
       "//chrome/services/media_gallery_util/public/cpp",
+      "//components/accuracy_tips",
       "//components/constrained_window",
       "//components/enterprise/common/proto:device_trust_report_event_proto",
       "//components/feedback",
@@ -7004,10 +7007,10 @@
       "chromeos/input_method/mock_input_method_manager_impl.h",
       "chromeos/net/network_portal_detector_test_utils.cc",
       "chromeos/net/network_portal_detector_test_utils.h",
-      "chromeos/policy/cloud_external_data_manager_base_test_util.cc",
-      "chromeos/policy/cloud_external_data_manager_base_test_util.h",
       "chromeos/policy/device_policy_builder.cc",
       "chromeos/policy/device_policy_builder.h",
+      "chromeos/policy/external_data/cloud_external_data_manager_base_test_util.cc",
+      "chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h",
       "chromeos/policy/fake_device_cloud_policy_initializer.cc",
       "chromeos/policy/fake_device_cloud_policy_initializer.h",
       "chromeos/policy/fake_device_cloud_policy_manager.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index c649ece4..c3f4bb9 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -40,6 +40,7 @@
   "+components/account_id",
   "+components/federated_learning",
   "+components/arc",
+  "+components/accuracy_tips",
   "+components/account_manager_core",
   "+components/assist_ranker",
   "+components/autofill_assistant/browser",
diff --git a/chrome/browser/accuracy_tips/OWNERS b/chrome/browser/accuracy_tips/OWNERS
new file mode 100644
index 0000000..8cc85eb
--- /dev/null
+++ b/chrome/browser/accuracy_tips/OWNERS
@@ -0,0 +1 @@
+file://components/accuracy_tips/OWNERS
diff --git a/chrome/browser/accuracy_tips/accuracy_service_factory.cc b/chrome/browser/accuracy_tips/accuracy_service_factory.cc
new file mode 100644
index 0000000..49a69a53
--- /dev/null
+++ b/chrome/browser/accuracy_tips/accuracy_service_factory.cc
@@ -0,0 +1,38 @@
+// Copyright 2021 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 "chrome/browser/accuracy_tips/accuracy_service_factory.h"
+
+#include "base/feature_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/accuracy_tips/accuracy_service.h"
+#include "components/accuracy_tips/accuracy_tip_ui.h"
+#include "components/accuracy_tips/features.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+// static
+accuracy_tips::AccuracyService* AccuracyServiceFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<accuracy_tips::AccuracyService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, /*create=*/true));
+}
+// static
+AccuracyServiceFactory* AccuracyServiceFactory::GetInstance() {
+  return base::Singleton<AccuracyServiceFactory>::get();
+}
+
+AccuracyServiceFactory::AccuracyServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "AccuracyServiceFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+AccuracyServiceFactory::~AccuracyServiceFactory() = default;
+
+// BrowserContextKeyedServiceFactory:
+KeyedService* AccuracyServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* profile) const {
+  DCHECK(base::FeatureList::IsEnabled(accuracy_tips::kAccuracyTipsFeature));
+  // TODO(crbug.com/1210891): Implement UI.
+  return new accuracy_tips::AccuracyService(nullptr);
+}
diff --git a/chrome/browser/accuracy_tips/accuracy_service_factory.h b/chrome/browser/accuracy_tips/accuracy_service_factory.h
new file mode 100644
index 0000000..fc6d975
--- /dev/null
+++ b/chrome/browser/accuracy_tips/accuracy_service_factory.h
@@ -0,0 +1,38 @@
+// Copyright 2021 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 CHROME_BROWSER_ACCURACY_TIPS_ACCURACY_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_ACCURACY_TIPS_ACCURACY_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+
+namespace accuracy_tips {
+class AccuracyService;
+}
+
+// This factory helps construct and find the AccuracyService instance for a
+// Profile.
+class AccuracyServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static accuracy_tips::AccuracyService* GetForProfile(Profile* profile);
+  static AccuracyServiceFactory* GetInstance();
+
+  AccuracyServiceFactory(const AccuracyServiceFactory&) = delete;
+  AccuracyServiceFactory& operator=(const AccuracyServiceFactory&) = delete;
+
+ private:
+  friend struct base::DefaultSingletonTraits<AccuracyServiceFactory>;
+
+  AccuracyServiceFactory();
+  ~AccuracyServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const override;
+};
+
+#endif  // CHROME_BROWSER_ACCURACY_TIPS_ACCURACY_SERVICE_FACTORY_H_
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
index 07bb9eb4..ba88b587 100644
--- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
+++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
@@ -483,11 +483,4 @@
     public boolean shouldShowOpenInChromeMenuItem() {
         return true;
     }
-
-    /**
-     * @return Whether the incognito icon in the toolbar should be hidden in cct-incognito mode.
-     */
-    public boolean shouldHideIncognitoIconOnToolbarInCct() {
-        return false;
-    }
 }
diff --git a/chrome/browser/android/browsing_data/browsing_data_bridge.cc b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
index 51357a0..cf4c0a5f 100644
--- a/chrome/browser/android/browsing_data/browsing_data_bridge.cc
+++ b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
@@ -18,7 +18,6 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/scoped_observer.h"
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
 #include "chrome/android/chrome_jni_headers/BrowsingDataBridge_jni.h"
diff --git a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
index 5b0357f..f936b44 100644
--- a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
+++ b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/scoped_observer.h"
 #include "chrome/browser/apps/app_service/icon_key_util.h"
 #include "chrome/browser/ash/guest_os/guest_os_registry_service.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager.h"
diff --git a/chrome/browser/ash/file_system_provider/registry.cc b/chrome/browser/ash/file_system_provider/registry.cc
index ce8fa39..ab4d77de 100644
--- a/chrome/browser/ash/file_system_provider/registry.cc
+++ b/chrome/browser/ash/file_system_provider/registry.cc
@@ -22,6 +22,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "storage/browser/file_system/external_mount_points.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace chromeos {
 namespace file_system_provider {
@@ -149,16 +150,22 @@
         file_systems_per_extension->FindKey(it.key());
     DCHECK(file_system_value);
 
+    if (!file_system_value->GetAsDictionary(&file_system)) {
+      LOG(ERROR)
+          << "Malformed provided file system information in preferences.";
+      continue;
+    }
+
     std::string file_system_id;
     std::string display_name;
     bool writable = false;
     bool supports_notify_tag = false;
-    int opened_files_limit = 0;
+    absl::optional<int> opened_files_limit =
+        file_system->FindIntKey(kPrefKeyOpenedFilesLimit);
 
     // TODO(mtomasz): Move opened files limit to the mandatory list above in
     // M42.
-    if ((!file_system_value->GetAsDictionary(&file_system) ||
-         !file_system->GetStringWithoutPathExpansion(kPrefKeyFileSystemId,
+    if ((!file_system->GetStringWithoutPathExpansion(kPrefKeyFileSystemId,
                                                      &file_system_id) ||
          !file_system->GetStringWithoutPathExpansion(kPrefKeyDisplayName,
                                                      &display_name) ||
@@ -168,9 +175,7 @@
                                                       &supports_notify_tag) ||
          file_system_id.empty() || display_name.empty()) ||
         // Optional fields.
-        (file_system->GetIntegerWithoutPathExpansion(kPrefKeyOpenedFilesLimit,
-                                                     &opened_files_limit) &&
-         opened_files_limit < 0)) {
+        (opened_files_limit.has_value() && opened_files_limit.value() < 0)) {
       LOG(ERROR)
           << "Malformed provided file system information in preferences.";
       continue;
@@ -181,7 +186,7 @@
     options.display_name = display_name;
     options.writable = writable;
     options.supports_notify_tag = supports_notify_tag;
-    options.opened_files_limit = opened_files_limit;
+    options.opened_files_limit = opened_files_limit.value_or(0);
 
     RestoredFileSystem restored_file_system;
     restored_file_system.provider_id = provider_id;
diff --git a/chrome/browser/ash/file_system_provider/registry_unittest.cc b/chrome/browser/ash/file_system_provider/registry_unittest.cc
index d077681..0ee70ec1 100644
--- a/chrome/browser/ash/file_system_provider/registry_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/registry_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/user_prefs/user_prefs.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace chromeos {
 namespace file_system_provider {
@@ -212,10 +213,10 @@
       kPrefKeySupportsNotifyTag, &supports_notify_tag));
   EXPECT_TRUE(supports_notify_tag);
 
-  int opened_files_limit = 0;
-  EXPECT_TRUE(file_system->GetIntegerWithoutPathExpansion(
-      kPrefKeyOpenedFilesLimit, &opened_files_limit));
-  EXPECT_EQ(kOpenedFilesLimit, opened_files_limit);
+  absl::optional<int> opened_files_limit =
+      file_system->FindIntKey(kPrefKeyOpenedFilesLimit);
+  EXPECT_TRUE(opened_files_limit.has_value());
+  EXPECT_EQ(kOpenedFilesLimit, opened_files_limit.value());
 
   const base::DictionaryValue* watchers_value = NULL;
   ASSERT_TRUE(file_system->GetDictionaryWithoutPathExpansion(kPrefKeyWatchers,
diff --git a/chrome/browser/ash/login/app_mode/kiosk_browsertest.cc b/chrome/browser/ash/login/app_mode/kiosk_browsertest.cc
index 180473c..e01015a8 100644
--- a/chrome/browser/ash/login/app_mode/kiosk_browsertest.cc
+++ b/chrome/browser/ash/login/app_mode/kiosk_browsertest.cc
@@ -432,7 +432,7 @@
 // Replaces settings urls for KioskSettingsNavigationThrottle.
 class ScopedSettingsPages {
  public:
-  explicit ScopedSettingsPages(
+  ScopedSettingsPages(
       std::vector<KioskSettingsNavigationThrottle::SettingsPage>* pages) {
     KioskSettingsNavigationThrottle::SetSettingPagesForTesting(pages);
   }
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc
index 0b11503..bf0670fd 100644
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc
@@ -48,6 +48,7 @@
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user.h"
 #include "components/version_info/version_info.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
 namespace {
@@ -216,15 +217,16 @@
 
   const base::DictionaryValue* dict =
       local_state->GetDictionary(prefs::kEasyUnlockHardlockState);
-  int state_int;
-  if (dict && dict->GetIntegerWithoutPathExpansion(account_id.GetUserEmail(),
-                                                   &state_int)) {
-    *state =
-        static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state_int);
-    return true;
-  }
+  if (!dict)
+    return false;
 
-  return false;
+  absl::optional<int> state_int = dict->FindIntKey(account_id.GetUserEmail());
+  if (!state_int.has_value())
+    return false;
+
+  *state = static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(
+      state_int.value());
+  return true;
 }
 
 EasyUnlockScreenlockStateHandler*
diff --git a/chrome/browser/ash/login/marketing_backend_connector.h b/chrome/browser/ash/login/marketing_backend_connector.h
index beccfff1..bc73248 100644
--- a/chrome/browser/ash/login/marketing_backend_connector.h
+++ b/chrome/browser/ash/login/marketing_backend_connector.h
@@ -95,7 +95,7 @@
 // Scoped callback setter for the MarketingBackendConnector
 class ScopedRequestCallbackSetter {
  public:
-  explicit ScopedRequestCallbackSetter(
+  ScopedRequestCallbackSetter(
       std::unique_ptr<base::RepeatingCallback<void(std::string)>> callback);
   ~ScopedRequestCallbackSetter();
 
diff --git a/chrome/browser/ash/login/oobe_interactive_ui_test.cc b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
index 77ebb270..be81a880f 100644
--- a/chrome/browser/ash/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
@@ -477,7 +477,7 @@
 class NativeWindowVisibilityBrowserMainExtraParts
     : public ChromeBrowserMainExtraParts {
  public:
-  explicit NativeWindowVisibilityBrowserMainExtraParts(
+  NativeWindowVisibilityBrowserMainExtraParts(
       NativeWindowVisibilityObserver* observer)
       : observer_(observer) {}
   ~NativeWindowVisibilityBrowserMainExtraParts() override = default;
diff --git a/chrome/browser/ash/login/signin/oauth2_browsertest.cc b/chrome/browser/ash/login/signin/oauth2_browsertest.cc
index 838f1089..6ccfcd08 100644
--- a/chrome/browser/ash/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/ash/login/signin/oauth2_browsertest.cc
@@ -67,6 +67,7 @@
 #include "net/cookies/canonical_cookie.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 using net::test_server::BasicHttpResponse;
 using net::test_server::HttpRequest;
@@ -347,15 +348,18 @@
     PrefService* local_state = g_browser_process->local_state();
     const base::DictionaryValue* prefs_oauth_status =
         local_state->GetDictionary("OAuthTokenStatus");
-    int oauth_token_status = user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN;
-    if (prefs_oauth_status &&
-        prefs_oauth_status->GetIntegerWithoutPathExpansion(
-            email, &oauth_token_status)) {
-      user_manager::User::OAuthTokenStatus result =
-          static_cast<user_manager::User::OAuthTokenStatus>(oauth_token_status);
-      return result;
-    }
-    return user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN;
+    if (!prefs_oauth_status)
+      return user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN;
+
+    absl::optional<int> oauth_token_status =
+        prefs_oauth_status->FindIntKey(email);
+    if (!oauth_token_status.has_value())
+      return user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN;
+
+    user_manager::User::OAuthTokenStatus result =
+        static_cast<user_manager::User::OAuthTokenStatus>(
+            oauth_token_status.value());
+    return result;
   }
 
   signin::IdentityManager* identity_manager() {
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc
index a451e2c..018151b 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc
@@ -39,8 +39,8 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_downloader.h"
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
index b35a435..4d075550 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -60,11 +60,11 @@
 #include "chrome/browser/chromeos/extensions/permissions_updater_delegate_chromeos.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "chrome/browser/chromeos/session_length_limiter.h"
diff --git a/chrome/browser/ash/login/users/supervised_user_manager_impl.cc b/chrome/browser/ash/login/users/supervised_user_manager_impl.cc
index d7b7d78..33b1c51 100644
--- a/chrome/browser/ash/login/users/supervised_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/supervised_user_manager_impl.cc
@@ -22,6 +22,7 @@
 #include "components/user_manager/user_type.h"
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 using content::BrowserThread;
 
@@ -160,11 +161,16 @@
 void SupervisedUserManagerImpl::SetPasswordInformation(
     const std::string& user_id,
     const base::DictionaryValue* password_info) {
-  int value;
-  if (password_info->GetIntegerWithoutPathExpansion(kSchemaVersion, &value))
-    SetUserIntegerValue(user_id, kSupervisedUserPasswordSchema, value);
-  if (password_info->GetIntegerWithoutPathExpansion(kPasswordRevision, &value))
-    SetUserIntegerValue(user_id, kSupervisedUserPasswordRevision, value);
+  absl::optional<int> schema_version =
+      password_info->FindIntKey(kSchemaVersion);
+  if (schema_version.has_value())
+    SetUserIntegerValue(user_id, kSupervisedUserPasswordSchema,
+                        schema_version.value());
+  absl::optional<int> password_revision =
+      password_info->FindIntKey(kPasswordRevision);
+  if (password_revision.has_value())
+    SetUserIntegerValue(user_id, kSupervisedUserPasswordRevision,
+                        password_revision.value());
 
   bool flag;
   if (password_info->GetBooleanWithoutPathExpansion(kRequirePasswordUpdate,
@@ -194,7 +200,12 @@
                                                     int* out_value) const {
   PrefService* local_state = g_browser_process->local_state();
   const base::DictionaryValue* dictionary = local_state->GetDictionary(key);
-  return dictionary->GetIntegerWithoutPathExpansion(user_id, out_value);
+  absl::optional<int> value = dictionary->FindIntKey(user_id);
+  if (!value)
+    return false;
+
+  *out_value = value.value();
+  return true;
 }
 
 bool SupervisedUserManagerImpl::GetUserBooleanValue(const std::string& user_id,
diff --git a/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc b/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc
index e9e1212b..87e7612b 100644
--- a/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc
+++ b/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc
@@ -32,8 +32,8 @@
 #include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client_impl.h"
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash.cc b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
index 5a9212b..6577349 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_ash.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
@@ -46,6 +46,7 @@
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_nss_types.h"
 #include "crypto/signature_creator.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace em = enterprise_management;
 
@@ -497,12 +498,12 @@
                   kAccountsPrefDeviceLocalAccountsKeyId, &account_id)) {
             account->set_account_id(account_id);
           }
-          int type;
-          if (entry_dict->GetIntegerWithoutPathExpansion(
-                  kAccountsPrefDeviceLocalAccountsKeyType, &type)) {
+          absl::optional<int> type =
+              entry_dict->FindIntKey(kAccountsPrefDeviceLocalAccountsKeyType);
+          if (type.has_value()) {
             account->set_type(
                 static_cast<em::DeviceLocalAccountInfoProto::AccountType>(
-                    type));
+                    type.value()));
           }
           std::string kiosk_app_id;
           if (entry_dict->GetStringWithoutPathExpansion(
diff --git a/chrome/browser/ash/power/auto_screen_brightness/model_config_loader_impl.h b/chrome/browser/ash/power/auto_screen_brightness/model_config_loader_impl.h
index ee2e7522..b0e6744 100644
--- a/chrome/browser/ash/power/auto_screen_brightness/model_config_loader_impl.h
+++ b/chrome/browser/ash/power/auto_screen_brightness/model_config_loader_impl.h
@@ -13,7 +13,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/ash/power/auto_screen_brightness/model_config.h"
 #include "chrome/browser/ash/power/auto_screen_brightness/model_config_loader.h"
diff --git a/chrome/browser/ash/release_notes/OWNERS b/chrome/browser/ash/release_notes/OWNERS
index acf56285..3a4a625 100644
--- a/chrome/browser/ash/release_notes/OWNERS
+++ b/chrome/browser/ash/release_notes/OWNERS
@@ -1 +1 @@
-file://ash/content/help_app_ui/OWNERS
+file://chromeos/components/help_app_ui/OWNERS
diff --git a/chrome/browser/ash/remote_apps/remote_apps_impl.h b/chrome/browser/ash/remote_apps/remote_apps_impl.h
index 82950572..a1599716 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_impl.h
+++ b/chrome/browser/ash/remote_apps/remote_apps_impl.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/ash/remote_apps/remote_apps_types.h"
 #include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/chrome/browser/ash/web_applications/help_app/OWNERS b/chrome/browser/ash/web_applications/help_app/OWNERS
index acf56285..3a4a625 100644
--- a/chrome/browser/ash/web_applications/help_app/OWNERS
+++ b/chrome/browser/ash/web_applications/help_app/OWNERS
@@ -1 +1 @@
-file://ash/content/help_app_ui/OWNERS
+file://chromeos/components/help_app_ui/OWNERS
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
index 6e6bbcc..f382959 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
@@ -6,11 +6,6 @@
 #include <vector>
 
 #include "ash/constants/ash_features.h"
-#include "ash/content/help_app_ui/help_app_manager.h"
-#include "ash/content/help_app_ui/help_app_manager_factory.h"
-#include "ash/content/help_app_ui/search/search.mojom.h"
-#include "ash/content/help_app_ui/search/search_handler.h"
-#include "ash/content/help_app_ui/url_constants.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -43,6 +38,11 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chromeos/components/help_app_ui/help_app_manager.h"
+#include "chromeos/components/help_app_ui/help_app_manager_factory.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/web_applications/test/sandboxed_web_ui_test_base.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/user_manager/user_names.h"
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.cc b/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.cc
index e770c52b0..5ca6fef5 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.cc
@@ -7,7 +7,6 @@
 #include <string>
 
 #include "ash/constants/ash_features.h"
-#include "ash/content/help_app_ui/url_constants.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "base/command_line.h"
@@ -27,6 +26,7 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "chromeos/system/statistics_provider.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.h b/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.h
index e2e8642..a69c5b2a 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.h
+++ b/chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_ASH_WEB_APPLICATIONS_HELP_APP_HELP_APP_UI_DELEGATE_H_
 #define CHROME_BROWSER_ASH_WEB_APPLICATIONS_HELP_APP_HELP_APP_UI_DELEGATE_H_
 
-#include "ash/content/help_app_ui/help_app_ui_delegate.h"
+#include "chromeos/components/help_app_ui/help_app_ui_delegate.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace content {
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc b/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc
index 3146e59..ce18be3 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_web_app_info.cc
@@ -6,11 +6,11 @@
 
 #include <memory>
 
-#include "ash/content/help_app_ui/url_constants.h"
-#include "ash/grit/ash_help_app_resources.h"
 #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
+#include "chromeos/grit/chromeos_help_app_resources.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/display/screen.h"
diff --git a/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc b/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
index 3a51ffb0..b2ffc59 100644
--- a/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
+++ b/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index c0a1e82..3180fd44 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -21,7 +21,6 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 3186f75..1cc029a 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -159,9 +159,6 @@
 #endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/content/help_app_ui/help_app_ui.h"
-#include "ash/content/help_app_ui/help_app_ui.mojom.h"
-#include "ash/content/help_app_ui/search/search.mojom.h"
 #include "ash/content/scanning/mojom/scanning.mojom.h"
 #include "ash/content/scanning/scanning_ui.h"
 #include "chrome/browser/apps/digital_goods/digital_goods_factory_impl.h"
@@ -202,6 +199,9 @@
 #include "chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom.h"
 #include "chromeos/components/eche_app_ui/eche_app_ui.h"
 #include "chromeos/components/eche_app_ui/mojom/eche_app.mojom.h"
+#include "chromeos/components/help_app_ui/help_app_ui.h"
+#include "chromeos/components/help_app_ui/help_app_ui.mojom.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
 #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
 #include "chromeos/components/media_app_ui/media_app_ui.h"
 #include "chromeos/components/media_app_ui/media_app_ui.mojom.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index ab233cbc..2ffe9581 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -80,13 +80,11 @@
     "//ash/components/audio",
     "//ash/components/os_feedback_ui",
     "//ash/components/pcie_peripheral",
-    "//ash/components/resources:help_app_resources_grit",
     "//ash/components/resources:os_feedback_resources_grit",
     "//ash/components/resources:scanning_app_resources_grit",
     "//ash/components/resources:shimless_rma_resources_grit",
     "//ash/components/resources:shortcut_customization_app_resources_grit",
     "//ash/constants",
-    "//ash/content/help_app_ui",
     "//ash/content/scanning",
     "//ash/content/scanning/mojom",
     "//ash/content/shimless_rma",
@@ -146,6 +144,7 @@
     "//chromeos/components/drivefs/mojom",
     "//chromeos/components/eche_app_ui",
     "//chromeos/components/feature_usage",
+    "//chromeos/components/help_app_ui",
     "//chromeos/components/local_search_service/public/cpp:cpp",
     "//chromeos/components/media_app_ui",
     "//chromeos/components/mojo_bootstrap",
@@ -241,6 +240,7 @@
     "//chromeos/resources:connectivity_diagnostics_resources_grit",
     "//chromeos/resources:diagnostics_app_resources_grit",
     "//chromeos/resources:eche_bundle_resources_grit",
+    "//chromeos/resources:help_app_resources_grit",
     "//chromeos/resources:media_app_resources_grit",
     "//chromeos/resources:personalization_app_resources_grit",
     "//chromeos/resources:print_management_resources_grit",
@@ -2582,20 +2582,12 @@
     "policy/browser_policy_connector_chromeos.h",
     "policy/cached_policy_key_loader_chromeos.cc",
     "policy/cached_policy_key_loader_chromeos.h",
-    "policy/cloud_external_data_manager_base.cc",
-    "policy/cloud_external_data_manager_base.h",
-    "policy/cloud_external_data_policy_observer.cc",
-    "policy/cloud_external_data_policy_observer.h",
-    "policy/cloud_external_data_store.cc",
-    "policy/cloud_external_data_store.h",
     "policy/component_active_directory_policy_retriever.cc",
     "policy/component_active_directory_policy_retriever.h",
     "policy/component_active_directory_policy_service.cc",
     "policy/component_active_directory_policy_service.h",
     "policy/configuration_policy_handler_chromeos.cc",
     "policy/configuration_policy_handler_chromeos.h",
-    "policy/device_cloud_external_data_policy_observer.cc",
-    "policy/device_cloud_external_data_policy_observer.h",
     "policy/device_cloud_policy_initializer.cc",
     "policy/device_cloud_policy_initializer.h",
     "policy/device_cloud_policy_manager_chromeos.cc",
@@ -2612,10 +2604,6 @@
     "policy/device_local_account.h",
     "policy/device_local_account_extension_tracker.cc",
     "policy/device_local_account_extension_tracker.h",
-    "policy/device_local_account_external_data_manager.cc",
-    "policy/device_local_account_external_data_manager.h",
-    "policy/device_local_account_external_data_service.cc",
-    "policy/device_local_account_external_data_service.h",
     "policy/device_local_account_policy_provider.cc",
     "policy/device_local_account_policy_provider.h",
     "policy/device_local_account_policy_service.cc",
@@ -2624,8 +2612,6 @@
     "policy/device_local_account_policy_store.h",
     "policy/device_network_configuration_updater.cc",
     "policy/device_network_configuration_updater.h",
-    "policy/device_policy_cloud_external_data_manager.cc",
-    "policy/device_policy_cloud_external_data_manager.h",
     "policy/device_policy_decoder_chromeos.cc",
     "policy/device_policy_decoder_chromeos.h",
     "policy/device_policy_remover.h",
@@ -2676,28 +2662,42 @@
     "policy/enrollment_handler_chromeos.h",
     "policy/enrollment_requisition_manager.cc",
     "policy/enrollment_requisition_manager.h",
-    "policy/external_data_handlers/cloud_external_data_policy_handler.cc",
-    "policy/external_data_handlers/cloud_external_data_policy_handler.h",
-    "policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc",
-    "policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h",
-    "policy/external_data_handlers/device_cloud_external_data_policy_handler.cc",
-    "policy/external_data_handlers/device_cloud_external_data_policy_handler.h",
-    "policy/external_data_handlers/device_print_servers_external_data_handler.cc",
-    "policy/external_data_handlers/device_print_servers_external_data_handler.h",
-    "policy/external_data_handlers/device_printers_external_data_handler.cc",
-    "policy/external_data_handlers/device_printers_external_data_handler.h",
-    "policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc",
-    "policy/external_data_handlers/device_wallpaper_image_external_data_handler.h",
-    "policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc",
-    "policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h",
-    "policy/external_data_handlers/print_servers_external_data_handler.cc",
-    "policy/external_data_handlers/print_servers_external_data_handler.h",
-    "policy/external_data_handlers/printers_external_data_handler.cc",
-    "policy/external_data_handlers/printers_external_data_handler.h",
-    "policy/external_data_handlers/user_avatar_image_external_data_handler.cc",
-    "policy/external_data_handlers/user_avatar_image_external_data_handler.h",
-    "policy/external_data_handlers/wallpaper_image_external_data_handler.cc",
-    "policy/external_data_handlers/wallpaper_image_external_data_handler.h",
+    "policy/external_data/cloud_external_data_manager_base.cc",
+    "policy/external_data/cloud_external_data_manager_base.h",
+    "policy/external_data/cloud_external_data_policy_observer.cc",
+    "policy/external_data/cloud_external_data_policy_observer.h",
+    "policy/external_data/device_cloud_external_data_policy_observer.cc",
+    "policy/external_data/device_cloud_external_data_policy_observer.h",
+    "policy/external_data/device_local_account_external_data_manager.cc",
+    "policy/external_data/device_local_account_external_data_manager.h",
+    "policy/external_data/device_local_account_external_data_service.cc",
+    "policy/external_data/device_local_account_external_data_service.h",
+    "policy/external_data/device_policy_cloud_external_data_manager.cc",
+    "policy/external_data/device_policy_cloud_external_data_manager.h",
+    "policy/external_data/handlers/cloud_external_data_policy_handler.cc",
+    "policy/external_data/handlers/cloud_external_data_policy_handler.h",
+    "policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc",
+    "policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h",
+    "policy/external_data/handlers/device_cloud_external_data_policy_handler.cc",
+    "policy/external_data/handlers/device_cloud_external_data_policy_handler.h",
+    "policy/external_data/handlers/device_print_servers_external_data_handler.cc",
+    "policy/external_data/handlers/device_print_servers_external_data_handler.h",
+    "policy/external_data/handlers/device_printers_external_data_handler.cc",
+    "policy/external_data/handlers/device_printers_external_data_handler.h",
+    "policy/external_data/handlers/device_wallpaper_image_external_data_handler.cc",
+    "policy/external_data/handlers/device_wallpaper_image_external_data_handler.h",
+    "policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.cc",
+    "policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.h",
+    "policy/external_data/handlers/print_servers_external_data_handler.cc",
+    "policy/external_data/handlers/print_servers_external_data_handler.h",
+    "policy/external_data/handlers/printers_external_data_handler.cc",
+    "policy/external_data/handlers/printers_external_data_handler.h",
+    "policy/external_data/handlers/user_avatar_image_external_data_handler.cc",
+    "policy/external_data/handlers/user_avatar_image_external_data_handler.h",
+    "policy/external_data/handlers/wallpaper_image_external_data_handler.cc",
+    "policy/external_data/handlers/wallpaper_image_external_data_handler.h",
+    "policy/external_data/user_cloud_external_data_manager.cc",
+    "policy/external_data/user_cloud_external_data_manager.h",
     "policy/fake_auto_enrollment_client.cc",
     "policy/fake_auto_enrollment_client.h",
     "policy/heartbeat_scheduler.cc",
@@ -2855,8 +2855,6 @@
     "policy/upload_job.h",
     "policy/upload_job_impl.cc",
     "policy/upload_job_impl.h",
-    "policy/user_cloud_external_data_manager.cc",
-    "policy/user_cloud_external_data_manager.h",
     "policy/user_cloud_policy_manager_chromeos.cc",
     "policy/user_cloud_policy_manager_chromeos.h",
     "policy/user_cloud_policy_store_chromeos.cc",
@@ -4073,9 +4071,6 @@
     "policy/auto_enrollment_client_impl_unittest.cc",
     "policy/bluetooth_policy_handler_unittest.cc",
     "policy/cached_policy_key_loader_chromeos_unittest.cc",
-    "policy/cloud_external_data_manager_base_unittest.cc",
-    "policy/cloud_external_data_policy_observer_unittest.cc",
-    "policy/cloud_external_data_store_unittest.cc",
     "policy/component_active_directory_policy_retriever_unittest.cc",
     "policy/component_active_directory_policy_service_unittest.cc",
     "policy/configuration_policy_handler_chromeos_unittest.cc",
@@ -4104,8 +4099,10 @@
     "policy/dlp/mock_dlp_rules_manager.h",
     "policy/dm_token_storage_unittest.cc",
     "policy/extension_cache_unittest.cc",
-    "policy/external_data_handlers/device_print_servers_external_data_handler_unittest.cc",
-    "policy/external_data_handlers/device_printers_external_data_handler_unittest.cc",
+    "policy/external_data/cloud_external_data_manager_base_unittest.cc",
+    "policy/external_data/cloud_external_data_policy_observer_unittest.cc",
+    "policy/external_data/handlers/device_print_servers_external_data_handler_unittest.cc",
+    "policy/external_data/handlers/device_printers_external_data_handler_unittest.cc",
     "policy/fake_affiliated_invalidation_service_provider.cc",
     "policy/fake_affiliated_invalidation_service_provider.h",
     "policy/heartbeat_scheduler_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index be68f16..59af77a 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -545,9 +545,9 @@
     case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTFULLSCREEN:
       return chromeos::WindowStateType::kFullscreen;
     case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPLEFT:
-      return chromeos::WindowStateType::kLeftSnapped;
+      return chromeos::WindowStateType::kPrimarySnapped;
     case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPRIGHT:
-      return chromeos::WindowStateType::kRightSnapped;
+      return chromeos::WindowStateType::kSecondarySnapped;
     default:
       NOTREACHED();
       return chromeos::WindowStateType::kNormal;
@@ -565,9 +565,9 @@
     case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTFULLSCREEN:
       return ash::WMEventType::WM_EVENT_FULLSCREEN;
     case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPLEFT:
-      return ash::WMEventType::WM_EVENT_SNAP_LEFT;
+      return ash::WMEventType::WM_EVENT_SNAP_PRIMARY;
     case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPRIGHT:
-      return ash::WMEventType::WM_EVENT_SNAP_RIGHT;
+      return ash::WMEventType::WM_EVENT_SNAP_SECONDARY;
     default:
       NOTREACHED();
       return ash::WMEventType::WM_EVENT_NORMAL;
@@ -590,10 +590,10 @@
     case chromeos::WindowStateType::kFullscreen:
       return api::autotest_private::WindowStateType::
           WINDOW_STATE_TYPE_FULLSCREEN;
-    case chromeos::WindowStateType::kLeftSnapped:
+    case chromeos::WindowStateType::kPrimarySnapped:
       return api::autotest_private::WindowStateType::
           WINDOW_STATE_TYPE_LEFTSNAPPED;
-    case chromeos::WindowStateType::kRightSnapped:
+    case chromeos::WindowStateType::kSecondarySnapped:
       return api::autotest_private::WindowStateType::
           WINDOW_STATE_TYPE_RIGHTSNAPPED;
     case chromeos::WindowStateType::kPip:
@@ -3944,11 +3944,11 @@
 
   // TODO(crbug.com/990713): Make WMEvent trigger split view in tablet mode.
   if (ash::TabletMode::Get()->InTabletMode()) {
-    if (expected_state == chromeos::WindowStateType::kLeftSnapped) {
+    if (expected_state == chromeos::WindowStateType::kPrimarySnapped) {
       ash::SplitViewTestApi().SnapWindow(
           window, ash::SplitViewTestApi::SnapPosition::LEFT);
       return RespondLater();
-    } else if (expected_state == chromeos::WindowStateType::kRightSnapped) {
+    } else if (expected_state == chromeos::WindowStateType::kSecondarySnapped) {
       ash::SplitViewTestApi().SnapWindow(
           window, ash::SplitViewTestApi::SnapPosition::RIGHT);
       return RespondLater();
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
index 3ecf6ecb..2e695e8 100644
--- a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
+++ b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
@@ -100,7 +100,7 @@
 constexpr gfx::Rect kRestoreBounds(100, 100);
 constexpr gfx::Rect kCurrentBounds(200, 200);
 constexpr chromeos::WindowStateType kWindowStateType =
-    chromeos::WindowStateType::kLeftSnapped;
+    chromeos::WindowStateType::kPrimarySnapped;
 
 void RemoveInactiveDesks() {
   // Removes all the inactive desks and waits for their async operations to
@@ -1474,10 +1474,10 @@
   // Snap |window| to the left and store its window properties.
   // TODO(sammiequon): Store and check desk id and restore bounds.
   auto* window_state = ash::WindowState::Get(window);
-  const ash::WMEvent left_snap_event(ash::WM_EVENT_SNAP_LEFT);
+  const ash::WMEvent left_snap_event(ash::WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&left_snap_event);
   const WindowStateType pre_save_state_type = window_state->GetStateType();
-  EXPECT_EQ(chromeos::WindowStateType::kLeftSnapped, pre_save_state_type);
+  EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped, pre_save_state_type);
   const gfx::Rect pre_save_bounds = window->GetBoundsInScreen();
 
   SaveWindowInfo(window);
diff --git a/chrome/browser/chromeos/full_restore/arc_ghost_window_delegate.cc b/chrome/browser/chromeos/full_restore/arc_ghost_window_delegate.cc
index 2d419265..2ebfb5d 100644
--- a/chrome/browser/chromeos/full_restore/arc_ghost_window_delegate.cc
+++ b/chrome/browser/chromeos/full_restore/arc_ghost_window_delegate.cc
@@ -116,10 +116,10 @@
   shell_surface_->SetBounds(display_id, bounds_in_display);
 
   if (requested_state != window_state->GetStateType()) {
-    DCHECK(requested_state == chromeos::WindowStateType::kLeftSnapped ||
-           requested_state == chromeos::WindowStateType::kRightSnapped);
+    DCHECK(requested_state == chromeos::WindowStateType::kPrimarySnapped ||
+           requested_state == chromeos::WindowStateType::kSecondarySnapped);
 
-    if (requested_state == chromeos::WindowStateType::kLeftSnapped)
+    if (requested_state == chromeos::WindowStateType::kPrimarySnapped)
       shell_surface_->SetSnappedToLeft();
     else
       shell_surface_->SetSnappedToRight();
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 0321848..7a1c24d0 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -42,15 +42,15 @@
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
-#include "chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/device_wifi_allowed_handler.h"
 #include "chrome/browser/chromeos/policy/dm_token_storage.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
 #include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/hostname_handler.h"
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler_delegate_impl.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account.cc b/chrome/browser/chromeos/policy/device_local_account.cc
index 001bb29..473a9036 100644
--- a/chrome/browser/chromeos/policy/device_local_account.cc
+++ b/chrome/browser/chromeos/policy/device_local_account.cc
@@ -21,6 +21,7 @@
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_names.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace policy {
 
@@ -260,10 +261,10 @@
       continue;
     }
 
-    int type;
-    if (!entry->GetIntegerWithoutPathExpansion(
-            chromeos::kAccountsPrefDeviceLocalAccountsKeyType, &type) ||
-        type < 0 || type >= DeviceLocalAccount::TYPE_COUNT) {
+    absl::optional<int> type =
+        entry->FindIntKey(chromeos::kAccountsPrefDeviceLocalAccountsKeyType);
+    if (!type || type.value() < 0 ||
+        type.value() >= DeviceLocalAccount::TYPE_COUNT) {
       LOG(ERROR) << "Missing or invalid account type in device-local account "
                  << "list at index " << i << ".";
       continue;
@@ -275,7 +276,7 @@
       continue;
     }
 
-    switch (type) {
+    switch (type.value()) {
       case DeviceLocalAccount::TYPE_PUBLIC_SESSION:
         accounts.push_back(DeviceLocalAccount(
             DeviceLocalAccount::TYPE_PUBLIC_SESSION, account_id, "", ""));
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 4d39863..22eab8a 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -74,11 +74,11 @@
 #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
 #include "chrome/browser/chromeos/extensions/external_cache.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/updater/chromeos_extension_cache_delegate.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
index 3823244..8183bfc0 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_service.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_provider.h b/chrome/browser/chromeos/policy/device_local_account_policy_provider.h
index bfe124c..dbb04a3 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_provider.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_provider.h
@@ -12,8 +12,8 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h"
 #include "components/policy/core/common/configuration_policy_provider.h"
 
 namespace policy {
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index 71454b2..3f9b83f 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -25,8 +25,8 @@
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.h b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
index d610e71..24d1acf5 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
@@ -20,7 +20,7 @@
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
 #include "chrome/browser/chromeos/policy/device_local_account_extension_tracker.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/core/common/cloud/component_cloud_policy_service.h"
diff --git a/chrome/browser/chromeos/policy/external_data/README.md b/chrome/browser/chromeos/policy/external_data/README.md
new file mode 100644
index 0000000..459929e
--- /dev/null
+++ b/chrome/browser/chromeos/policy/external_data/README.md
@@ -0,0 +1,17 @@
+chrome/browser/chromeos/policy/external_data
+============================================
+
+This directory should contain code that handles policies which rely on external
+data.
+
+Each policy has one of three different formats:
+* STRING, a free-form string value,
+* JSON, a valid string in the .json format,
+* EXTERNAL, an arbitrary file that has to be downloaded separately to the
+normal policy retrieval process.
+
+In the EXTERNAL case, the policy value is (internally) represented by a JSON
+string that contains the URL of the external file, and a hash for verification.
+The code in this directory is responsible for the retrieval, verification
+and caching of the external data. Behavior that is specific to individual
+policies is defined via handlers in the external_data/handlers/ subdirectory.
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.cc
similarity index 98%
rename from chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.cc
index e40fdb1..2d767e8 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.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/chromeos/policy/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -27,7 +27,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/core/common/cloud/external_policy_data_fetcher.h"
 #include "components/policy/core/common/cloud/external_policy_data_updater.h"
@@ -62,7 +62,7 @@
 
   // Allows downloaded external data to be cached in |external_data_store|.
   // Ownership of the store is taken. The store can be destroyed by calling
-  // SetExternalDataStore(std::unique_ptr<CloudExternalDataStore>()).
+  // SetExternalDataStore(nullptr).
   void SetExternalDataStore(
       std::unique_ptr<CloudExternalDataStore> external_data_store);
 
@@ -208,7 +208,7 @@
     external_data_store_->Prune(metadata_);
 
   for (FetchCallbackMap::iterator it = pending_downloads_.begin();
-       it != pending_downloads_.end(); ) {
+       it != pending_downloads_.end();) {
     const std::string policy = it->first;
     Metadata::const_iterator metadata = metadata_.find(policy);
     if (metadata == metadata_.end()) {
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.h b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h
similarity index 88%
rename from chrome/browser/chromeos/policy/cloud_external_data_manager_base.h
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h
index 31849475..1405ce9d 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.h
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.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 CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_BASE_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_BASE_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_MANAGER_BASE_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_MANAGER_BASE_H_
 
 #include <memory>
 
@@ -39,9 +39,8 @@
 
   // Allows downloaded external data to be cached in |external_data_store|.
   // Ownership of the store is taken. The store can be destroyed by calling
-  // SetExternalDataStore(std::unique_ptr<CloudExternalDataStore>()). Accesses
-  // to the
-  // store are made via |backend_task_runner_| only.
+  // SetExternalDataStore(nullptr). Accesses to the store are made via
+  // |backend_task_runner_| only.
   void SetExternalDataStore(
       std::unique_ptr<CloudExternalDataStore> external_data_store);
 
@@ -85,4 +84,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_BASE_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_MANAGER_BASE_H_
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.cc
index eab5ab4..ef3516dce 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.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/chromeos/policy/cloud_external_data_manager_base_test_util.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h
similarity index 86%
rename from chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h
index 747a627..e5ce791 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.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 CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_BASE_TEST_UTIL_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_BASE_TEST_UTIL_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_MANAGER_BASE_TEST_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_MANAGER_BASE_TEST_UTIL_H_
 
 #include <memory>
 #include <string>
@@ -59,4 +59,4 @@
 }  // namespace test
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_BASE_TEST_UTIL_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_MANAGER_BASE_TEST_UTIL_H_
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_unittest.cc
similarity index 95%
rename from chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_unittest.cc
index 0584eeb..f1cafa0 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_unittest.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/chromeos/policy/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
 
 #include <map>
 #include <memory>
@@ -19,7 +19,7 @@
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
 #include "components/policy/core/common/cloud/resource_cache.h"
 #include "components/policy/core/common/external_data_fetcher.h"
@@ -56,9 +56,9 @@
 
 const PolicyDetails kPolicyDetails[] = {
     // deprecated  future, device_policy  id    max_external_data_size
-    {  false,      false,  false,         1,    0},
-    {  false,      false,  false,         2,    10},
-    {  false,      false,  false,         3,    20},
+    {false, false, false, 1, 0},
+    {false, false, false, 2, 10},
+    {false, false, false, 3, 20},
 };
 
 const char kCacheKey[] = "data";
@@ -108,8 +108,7 @@
   DISALLOW_COPY_AND_ASSIGN(CloudExternalDataManagerBaseTest);
 };
 
-CloudExternalDataManagerBaseTest::CloudExternalDataManagerBaseTest() {
-}
+CloudExternalDataManagerBaseTest::CloudExternalDataManagerBaseTest() {}
 
 void CloudExternalDataManagerBaseTest::SetUp() {
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -124,14 +123,12 @@
                                       base::Value(std::string()), nullptr);
   // Make |k10BytePolicy| reference 10 bytes of external data.
   SetExternalDataReference(
-      k10BytePolicy,
-      ConstructMetadata(k10BytePolicyURL,
-                        crypto::SHA256HashString(k10ByteData)));
+      k10BytePolicy, ConstructMetadata(k10BytePolicyURL,
+                                       crypto::SHA256HashString(k10ByteData)));
   // Make |k20BytePolicy| reference 20 bytes of external data.
   SetExternalDataReference(
-      k20BytePolicy,
-      ConstructMetadata(k20BytePolicyURL,
-                        crypto::SHA256HashString(k20ByteData)));
+      k20BytePolicy, ConstructMetadata(k20BytePolicyURL,
+                                       crypto::SHA256HashString(k20ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
 
   url_loader_factory_ =
@@ -414,9 +411,8 @@
   // Modify the external data reference for |k20BytePolicy|, allowing the
   // download to be retried immediately.
   SetExternalDataReference(
-      k20BytePolicy,
-      ConstructMetadata(k20BytePolicyURL,
-                        crypto::SHA256HashString(k10ByteData)));
+      k20BytePolicy, ConstructMetadata(k20BytePolicyURL,
+                                       crypto::SHA256HashString(k10ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
 
   // Attempt to retrieve external data for |k20BytePolicy| again. Verify that
@@ -430,9 +426,8 @@
   // Modify the external data reference for |k20BytePolicy|, allowing the
   // download to be retried immediately.
   SetExternalDataReference(
-      k20BytePolicy,
-      ConstructMetadata(k20BytePolicyURL,
-                        crypto::SHA256HashString(k20ByteData)));
+      k20BytePolicy, ConstructMetadata(k20BytePolicyURL,
+                                       crypto::SHA256HashString(k20ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
 
   // Serve external data for |k20BytePolicy| that does not match the hash
@@ -451,9 +446,8 @@
   // download to be retried immediately. The external data reference now matches
   // the data being served.
   SetExternalDataReference(
-      k20BytePolicy,
-      ConstructMetadata(k20BytePolicyURL,
-                        crypto::SHA256HashString(k10ByteData)));
+      k20BytePolicy, ConstructMetadata(k20BytePolicyURL,
+                                       crypto::SHA256HashString(k10ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
 
   // Attempt to retrieve external data for |k20BytePolicy| again. Verify that
@@ -578,9 +572,8 @@
 
   // Modify the external data reference for |k20BytePolicy|.
   SetExternalDataReference(
-      k20BytePolicy,
-      ConstructMetadata(k20BytePolicyURL,
-                        crypto::SHA256HashString(k10ByteData)));
+      k20BytePolicy, ConstructMetadata(k20BytePolicyURL,
+                                       crypto::SHA256HashString(k10ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
 
   // Verify that the old external data for |k20BytePolicy| has been pruned from
@@ -627,9 +620,8 @@
   // Modify the external data reference for |k10BytePolicy| to match the
   // external data being served.
   SetExternalDataReference(
-      k10BytePolicy,
-      ConstructMetadata(k10BytePolicyURL,
-                        crypto::SHA256HashString(k20ByteData)));
+      k10BytePolicy, ConstructMetadata(k10BytePolicyURL,
+                                       crypto::SHA256HashString(k20ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
 
   // Retrieve external data for |k10BytePolicy|. Verify that the callback is
@@ -720,9 +712,8 @@
   // external data now being served. Verify that the callback is invoked with
   // the downloaded data.
   SetExternalDataReference(
-      k20BytePolicy,
-      ConstructMetadata(k20BytePolicyURL,
-                        crypto::SHA256HashString(k10ByteData)));
+      k20BytePolicy, ConstructMetadata(k20BytePolicyURL,
+                                       crypto::SHA256HashString(k10ByteData)));
   cloud_policy_store_.NotifyStoreLoaded();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, callback_data_.size());
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc b/chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.cc
similarity index 94%
rename from chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.cc
index 58a63cd..0aa03a4 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.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/chromeos/policy/cloud_external_data_policy_observer.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.h"
 
 #include <memory>
 #include <set>
@@ -56,9 +56,7 @@
     CloudExternalDataPolicyObserver* parent,
     const std::string& user_id,
     PolicyService* policy_service)
-    : parent_(parent),
-      user_id_(user_id),
-      policy_service_(policy_service) {
+    : parent_(parent), user_id_(user_id), policy_service_(policy_service) {
   policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this);
 
   if (!IsDeviceLocalAccountUser(user_id, NULL)) {
@@ -66,8 +64,9 @@
     // during login. This is omitted for device-local accounts because their
     // policy is available before login and the external data reference will
     // have been seen by the |parent_| already.
-    const PolicyMap::Entry* entry = policy_service_->GetPolicies(
-        PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+    const PolicyMap::Entry* entry =
+        policy_service_
+            ->GetPolicies(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
             .Get(parent_->policy_);
     // Notify |parent_| even when |entry| is null (i.e. the policy never existed
     // or once existed but was cleared later).
@@ -91,7 +90,7 @@
   if ((!previous_entry && current_entry) ||
       (previous_entry && !current_entry) ||
       (previous_entry && current_entry &&
-           !previous_entry->Equals(*current_entry))) {
+       !previous_entry->Equals(*current_entry))) {
     // Notify |parent_| if the external data reference for |user_id_| has
     // changed.
     parent_->HandleExternalDataPolicyUpdate(user_id_, current_entry);
@@ -100,13 +99,11 @@
 
 void CloudExternalDataPolicyObserver::Delegate::OnExternalDataSet(
     const std::string& policy,
-    const std::string& user_id) {
-}
+    const std::string& user_id) {}
 
 void CloudExternalDataPolicyObserver::Delegate::OnExternalDataCleared(
     const std::string& policy,
-    const std::string& user_id) {
-}
+    const std::string& user_id) {}
 
 void CloudExternalDataPolicyObserver::Delegate::OnExternalDataFetched(
     const std::string& policy,
@@ -114,8 +111,7 @@
     std::unique_ptr<std::string> data,
     const base::FilePath& file_path) {}
 
-CloudExternalDataPolicyObserver::Delegate::~Delegate() {
-}
+CloudExternalDataPolicyObserver::Delegate::~Delegate() {}
 
 CloudExternalDataPolicyObserver::CloudExternalDataPolicyObserver(
     ash::CrosSettings* cros_settings,
@@ -244,7 +240,7 @@
 
   for (DeviceLocalAccountEntryMap::iterator it =
            device_local_account_entries_.begin();
-       it != device_local_account_entries_.end(); ) {
+       it != device_local_account_entries_.end();) {
     if (!base::Contains(device_local_accounts, it->first)) {
       const std::string user_id = it->first;
       device_local_account_entries_.erase(it++);
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h b/chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.h
similarity index 94%
rename from chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.h
index 9ae8bb6d..d200bc7 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.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 CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
 
 #include <map>
 #include <memory>
@@ -134,4 +134,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer_unittest.cc
similarity index 97%
rename from chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
rename to chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer_unittest.cc
index e85f372..e6b3480 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer_unittest.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/chromeos/policy/cloud_external_data_policy_observer.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.h"
 
 #include <memory>
 #include <utility>
@@ -21,11 +21,11 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_provider.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_paths.h"
@@ -58,9 +58,9 @@
 
 namespace em = enterprise_management;
 
+using ::testing::_;
 using ::testing::Mock;
 using ::testing::Return;
-using ::testing::_;
 
 namespace policy {
 
@@ -80,8 +80,7 @@
   base::FilePath test_data_dir;
   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
   ASSERT_TRUE(base::ReadFileToString(
-      test_data_dir.Append("chromeos").Append(file_name),
-      policy_data));
+      test_data_dir.Append("chromeos").Append(file_name), policy_data));
   base::JSONWriter::Write(
       *test::ConstructExternalDataReference(url, *policy_data), policy);
 }
@@ -176,8 +175,7 @@
           DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
       profile_manager_(TestingBrowserProcess::GetGlobal()) {}
 
-CloudExternalDataPolicyObserverTest::~CloudExternalDataPolicyObserverTest() {
-}
+CloudExternalDataPolicyObserverTest::~CloudExternalDataPolicyObserverTest() {}
 
 void CloudExternalDataPolicyObserverTest::SetUp() {
   ash::DeviceSettingsTestBase::SetUp();
@@ -203,13 +201,9 @@
       .WillByDefault(Return(true));
   user_policy_provider_.Init();
 
-  ConstructAvatarPolicy("avatar1.jpg",
-                        kAvatar1URL,
-                        &avatar_policy_1_data_,
+  ConstructAvatarPolicy("avatar1.jpg", kAvatar1URL, &avatar_policy_1_data_,
                         &avatar_policy_1_);
-  ConstructAvatarPolicy("avatar2.jpg",
-                        kAvatar2URL,
-                        &avatar_policy_2_data_,
+  ConstructAvatarPolicy("avatar2.jpg", kAvatar2URL, &avatar_policy_2_data_,
                         &avatar_policy_2_);
 }
 
@@ -227,7 +221,6 @@
   ash::DeviceSettingsTestBase::TearDown();
 }
 
-
 void CloudExternalDataPolicyObserverTest::OnExternalDataSet(
     const std::string& policy,
     const std::string& user_id) {
@@ -319,7 +312,7 @@
 }
 
 DeviceLocalAccountPolicyBroker*
-    CloudExternalDataPolicyObserverTest::GetBrokerForDeviceLocalAccountUser() {
+CloudExternalDataPolicyObserverTest::GetBrokerForDeviceLocalAccountUser() {
   return device_local_account_policy_service_->GetBrokerForUser(
       device_local_account_user_id_);
 }
diff --git a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.cc b/chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.cc
rename to chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.cc
index 23695e0c..a7dca4f 100644
--- a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.cc
+++ b/chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.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/chromeos/policy/device_cloud_external_data_policy_observer.h"
+#include "chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.h"
 
 #include "base/bind.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
diff --git a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.h b/chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.h
similarity index 91%
rename from chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.h
rename to chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.h
index bce0c5e..2302b92 100644
--- a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.h
+++ b/chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.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 CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
 
 #include <memory>
 #include <string>
@@ -86,4 +86,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_OBSERVER_H_
diff --git a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc b/chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer_browsertest.cc
similarity index 97%
rename from chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc
rename to chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer_browsertest.cc
index d441e612..3a93afc 100644
--- a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc
+++ b/chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer_browsertest.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/chromeos/policy/device_cloud_external_data_policy_observer.h"
+#include "chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.h"
 
 #include <memory>
 #include <string>
@@ -14,8 +14,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/policy/core/common/policy_service.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_external_data_manager.cc b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.cc
similarity index 79%
rename from chrome/browser/chromeos/policy/device_local_account_external_data_manager.cc
rename to chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.cc
index 8d75aa1..966459d22 100644
--- a/chrome/browser/chromeos/policy/device_local_account_external_data_manager.cc
+++ b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.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/chromeos/policy/device_local_account_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h"
 
 #include <memory>
 
 #include "base/sequenced_task_runner.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 #include "components/policy/core/common/cloud/resource_cache.h"
 #include "components/policy/policy_constants.h"
 
@@ -26,7 +26,7 @@
 
 DeviceLocalAccountExternalDataManager::
     ~DeviceLocalAccountExternalDataManager() {
-  SetExternalDataStore(std::unique_ptr<CloudExternalDataStore>());
+  SetExternalDataStore(nullptr);
 }
 
 void DeviceLocalAccountExternalDataManager::OnPolicyStoreLoaded() {
diff --git a/chrome/browser/chromeos/policy/device_local_account_external_data_manager.h b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h
similarity index 86%
rename from chrome/browser/chromeos/policy/device_local_account_external_data_manager.h
rename to chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h
index 8c68aef..65a2c4f 100644
--- a/chrome/browser/chromeos/policy/device_local_account_external_data_manager.h
+++ b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.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_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_MANAGER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_MANAGER_H_
 
 #include <string>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
 #include "components/policy/core/common/policy_details.h"
 
 namespace base {
@@ -63,4 +63,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_MANAGER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_MANAGER_H_
diff --git a/chrome/browser/chromeos/policy/device_local_account_external_data_service.cc b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.cc
similarity index 89%
rename from chrome/browser/chromeos/policy/device_local_account_external_data_service.cc
rename to chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.cc
index 3b3a322..0f8eb0e 100644
--- a/chrome/browser/chromeos/policy/device_local_account_external_data_service.cc
+++ b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.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/chromeos/policy/device_local_account_external_data_service.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.h"
 
 #include <memory>
 #include <set>
@@ -48,13 +48,12 @@
 }
 
 void DeviceLocalAccountExternalDataService::OnPolicyUpdated(
-    const std::string& user_id) {
-}
+    const std::string& user_id) {}
 
 void DeviceLocalAccountExternalDataService::OnDeviceLocalAccountsChanged() {
   std::set<std::string> account_ids;
   for (ExternalDataManagerMap::iterator it = external_data_managers_.begin();
-       it != external_data_managers_.end(); ) {
+       it != external_data_managers_.end();) {
     if (it->second->HasOneRef()) {
       external_data_managers_.erase(it++);
     } else {
@@ -69,9 +68,9 @@
 }
 
 scoped_refptr<DeviceLocalAccountExternalDataManager>
-    DeviceLocalAccountExternalDataService::GetExternalDataManager(
-        const std::string& account_id,
-        CloudPolicyStore* policy_store) {
+DeviceLocalAccountExternalDataService::GetExternalDataManager(
+    const std::string& account_id,
+    CloudPolicyStore* policy_store) {
   scoped_refptr<DeviceLocalAccountExternalDataManager>& external_data_manager =
       external_data_managers_[account_id];
   if (!external_data_manager.get()) {
diff --git a/chrome/browser/chromeos/policy/device_local_account_external_data_service.h b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.h
similarity index 74%
rename from chrome/browser/chromeos/policy/device_local_account_external_data_service.h
rename to chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.h
index d74607d5..422d992 100644
--- a/chrome/browser/chromeos/policy/device_local_account_external_data_service.h
+++ b/chrome/browser/chromeos/policy/external_data/device_local_account_external_data_service.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 CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_SERVICE_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_SERVICE_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_SERVICE_H_
 
 #include <map>
 #include <memory>
@@ -12,8 +12,8 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/chromeos/policy/device_local_account_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
+#include "chrome/browser/chromeos/policy/external_data/device_local_account_external_data_manager.h"
 #include "components/policy/core/common/cloud/resource_cache.h"
 
 namespace base {
@@ -38,13 +38,13 @@
   void OnPolicyUpdated(const std::string& user_id) override;
   void OnDeviceLocalAccountsChanged() override;
 
-  scoped_refptr<DeviceLocalAccountExternalDataManager>
-      GetExternalDataManager(const std::string& account_id,
-                             CloudPolicyStore* policy_store);
+  scoped_refptr<DeviceLocalAccountExternalDataManager> GetExternalDataManager(
+      const std::string& account_id,
+      CloudPolicyStore* policy_store);
 
  private:
   typedef std::map<std::string,
-                   scoped_refptr<DeviceLocalAccountExternalDataManager> >
+                   scoped_refptr<DeviceLocalAccountExternalDataManager>>
       ExternalDataManagerMap;
 
   DeviceLocalAccountPolicyService* parent_;
@@ -58,4 +58,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_SERVICE_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA_SERVICE_H_
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.cc b/chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.cc
similarity index 91%
rename from chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.cc
rename to chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.cc
index 6ff8bad..ea924c6 100644
--- a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.cc
+++ b/chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.h"
 
 #include <stdint.h>
 #include <utility>
 
 #include "base/location.h"
 #include "base/sequenced_task_runner.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/core/common/cloud/resource_cache.h"
 #include "components/policy/policy_constants.h"
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h b/chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.h
similarity index 81%
rename from chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h
rename to chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.h
index 85f799b3..897e2a0 100644
--- a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h
+++ b/chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.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_CHROMEOS_POLICY_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
 
 #include <memory>
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
 #include "components/policy/core/common/policy_details.h"
 
 namespace base {
@@ -52,4 +52,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc b/chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager_browsertest.cc
similarity index 95%
rename from chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
rename to chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager_browsertest.cc
index 14c9829..3b4cd5dd 100644
--- a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager_browsertest.cc
@@ -19,11 +19,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
-#include "chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
+#include "chrome/browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.cc
similarity index 90%
rename from chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.cc
index 3639172..1cb339c 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_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/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h"
 
 #include "components/user_manager/known_user.h"
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h
similarity index 90%
rename from chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h
index 04e5157..8c80ce2 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
 
-#include "chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_policy_observer.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
similarity index 97%
rename from chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
index 9128b0b..db0bdf3 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_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/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h"
 
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h
index 255eed4..0b07d3f 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h"
 
 namespace ash {
 class CrosSettings;
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.cc
similarity index 84%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.cc
index f643e31..6d24c3ae 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_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/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h
similarity index 89%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h
index 415622f..6d8426c 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
 
-#include "chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.h"
+#include "chrome/browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.cc
index 3dd1192..e09942c 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_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/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.h
index d2dfe0b1..c8f51fbb 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/files/file_path.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler_unittest.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler_unittest.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler_unittest.cc
index 165caea..1bef167 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler_unittest.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/chromeos/policy/external_data_handlers/device_print_servers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_print_servers_external_data_handler.h"
 
 #include <memory>
 #include <string>
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.cc
similarity index 95%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.cc
index 447d094..8405932 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_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/chromeos/policy/external_data_handlers/device_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.h
index 12ab3fc4..14f2ae3 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h"
 
 namespace chromeos {
 class BulkPrintersCalculator;
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler_unittest.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler_unittest.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler_unittest.cc
index f276a07..a8b7cbeb 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_printers_external_data_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler_unittest.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/chromeos/policy/external_data_handlers/device_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_printers_external_data_handler.h"
 
 #include <memory>
 #include <string>
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.cc
index 5c0e75e..0e81569 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_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/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.h
index 964a9063..a083b63 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h"
 
 class PrefRegistrySimple;
 class PrefService;
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.cc
index 5ec81ca..e8dcf6e3 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_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/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.h"
 
 #include "chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
 #include "components/policy/policy_constants.h"
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.h
index 6f12691b..027c82b0 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_cloud_external_data_policy_handler.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc b/chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
similarity index 98%
rename from chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
index 65141f11..b71f408 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc
@@ -15,9 +15,9 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/policy/core/common/external_data_fetcher.h"
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.cc
index ec67f65..11293a2 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_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/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.h
index e68b211c..8d37dc0 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/print_servers_external_data_handler.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h"
 
 namespace ash {
 class CrosSettings;
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.cc
similarity index 97%
rename from chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.cc
index 8e7d7b65..bbd7c3b 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_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/chromeos/policy/external_data_handlers/printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.h
index 995176b6..e1cf011c 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/printers_external_data_handler.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h"
 
 namespace ash {
 class CrosSettings;
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.cc
index d90ae8c..c3ed965 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_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/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.h
index c77a1895..5cc0462 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/user_avatar_image_external_data_handler.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h"
 
 namespace ash {
 class CrosSettings;
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.cc
similarity index 96%
rename from chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.cc
index 2f2e49ed..233a9c3 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_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/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.h
similarity index 95%
rename from chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.h
index b7d4742..3015145 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data/handlers/wallpaper_image_external_data_handler.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/cloud_external_data_policy_handler.h"
 
 namespace ash {
 class CrosSettings;
diff --git a/chrome/browser/chromeos/policy/user_cloud_external_data_manager.cc b/chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.cc
similarity index 86%
rename from chrome/browser/chromeos/policy/user_cloud_external_data_manager.cc
rename to chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.cc
index 8d7a2d0..5e848a7c3 100644
--- a/chrome/browser/chromeos/policy/user_cloud_external_data_manager.cc
+++ b/chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.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/chromeos/policy/user_cloud_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.h"
 
 #include <memory>
 
 #include "base/location.h"
 #include "base/sequenced_task_runner.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/core/common/cloud/resource_cache.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -36,7 +36,7 @@
 }
 
 UserCloudExternalDataManager::~UserCloudExternalDataManager() {
-  SetExternalDataStore(std::unique_ptr<CloudExternalDataStore>());
+  SetExternalDataStore(nullptr);
   backend_task_runner_->DeleteSoon(FROM_HERE, resource_cache_);
 }
 
diff --git a/chrome/browser/chromeos/policy/user_cloud_external_data_manager.h b/chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.h
similarity index 87%
rename from chrome/browser/chromeos/policy/user_cloud_external_data_manager.h
rename to chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.h
index 4a962d2f..d8afa94b 100644
--- a/chrome/browser/chromeos/policy/user_cloud_external_data_manager.h
+++ b/chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.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_CHROMEOS_POLICY_USER_CLOUD_EXTERNAL_DATA_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_USER_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_USER_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_USER_CLOUD_EXTERNAL_DATA_MANAGER_H_
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
 #include "components/policy/core/common/policy_details.h"
 
 namespace base {
@@ -63,4 +63,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_USER_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_USER_CLOUD_EXTERNAL_DATA_MANAGER_H_
diff --git a/chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc b/chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager_browsertest.cc
similarity index 95%
rename from chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc
rename to chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager_browsertest.cc
index c739c766..f59b7f8 100644
--- a/chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager_browsertest.cc
@@ -14,8 +14,8 @@
 #include "base/run_loop.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
-#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/external_data/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/login_policy_test_base.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_policy_test_helper.h"
diff --git a/chrome/browser/chromeos/policy/reporting/README.md b/chrome/browser/chromeos/policy/reporting/README.md
new file mode 100644
index 0000000..0a4656d
--- /dev/null
+++ b/chrome/browser/chromeos/policy/reporting/README.md
@@ -0,0 +1,2 @@
+This directory contains code for real time reporting of events, such as ARC++
+apps or extensions installations.
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
index 57cdf5a2..bcdd9c76 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
@@ -25,7 +25,7 @@
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/active_directory_policy_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/user_cloud_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/external_data/user_cloud_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
diff --git a/chrome/browser/chromeos/printing/print_servers_manager.cc b/chrome/browser/chromeos/printing/print_servers_manager.cc
index fb0d6909..54911a5 100644
--- a/chrome/browser/chromeos/printing/print_servers_manager.cc
+++ b/chrome/browser/chromeos/printing/print_servers_manager.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/printing/cups_printer_status_creator.h"
 #include "chrome/browser/chromeos/printing/enterprise_printers_provider.h"
 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
diff --git a/chrome/browser/chromeos/printing/server_printers_provider.cc b/chrome/browser/chromeos/printing/server_printers_provider.cc
index 2637d7c..f4601545 100644
--- a/chrome/browser/chromeos/printing/server_printers_provider.cc
+++ b/chrome/browser/chromeos/printing/server_printers_provider.cc
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/scoped_observer.h"
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/chromeos/printing/print_servers_provider.h"
diff --git a/chrome/browser/data_saver/subresource_redirect_browsertest.cc b/chrome/browser/data_saver/subresource_redirect_browsertest.cc
index b1897f3f..755ec7a 100644
--- a/chrome/browser/data_saver/subresource_redirect_browsertest.cc
+++ b/chrome/browser/data_saver/subresource_redirect_browsertest.cc
@@ -1338,10 +1338,10 @@
   EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(),
             https_url().port());
 
-  VerifyCompressibleImageUkm(0);
+  VerifyCompressibleImageUkm(1);
   VerifyIneligibleImageHintsUnavailableUkm(0);
   VerifyIneligibleMissingInImageHintsUkm(0);
-  VerifyIneligibleOtherImageUkm(1);
+  VerifyIneligibleOtherImageUkm(0);
   VerifyImageCompressionPageInfoState(false);
 }
 
@@ -1670,9 +1670,9 @@
       "SubresourceRedirect.DidCompress.CompressionPercent", 0);
 
   WaitForImageCompressionUkmMetrics(1);
-  VerifyCompressibleImageUkm(0);
+  VerifyCompressibleImageUkm(1);
   VerifyIneligibleImageHintsUnavailableUkm(0);
   VerifyIneligibleMissingInImageHintsUkm(0);
-  VerifyIneligibleOtherImageUkm(1);
+  VerifyIneligibleOtherImageUkm(0);
   VerifyImageCompressionPageInfoState(false);
 }
diff --git a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
index 8d6066e..f9a87e9 100644
--- a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
+++ b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
@@ -146,24 +146,6 @@
     return merged_metrics;
   }
 
-  void VerifyRobotsRulesFetch(
-      const std::set<std::string>& expected_robots_requests) {
-    if (!expected_robots_requests.empty()) {
-      histogram_tester_.ExpectBucketCount(
-          "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK,
-          expected_robots_requests.size());
-      histogram_tester_.ExpectBucketCount(
-          "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false,
-          expected_robots_requests.size());
-    } else {
-      histogram_tester_.ExpectTotalCount(
-          "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
-      histogram_tester_.ExpectTotalCount(
-          "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
-    }
-    robots_rules_server_.VerifyRequestedOrigins(expected_robots_requests);
-  }
-
  protected:
   bool enable_lite_mode_;
   bool enable_login_robots_compression_feature_;
@@ -237,10 +219,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
 
@@ -286,10 +272,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths({});
 
   using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad;
@@ -336,9 +326,13 @@
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
   histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
+  histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
+  histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({});
+  robots_rules_server_.VerifyRequestedOrigins({});
   image_compression_server_.VerifyRequestedImagePaths({});
   VerifyImageCompressionPageInfoState(false);
 }
@@ -359,9 +353,13 @@
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
   histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
+  histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
+  histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({});
+  robots_rules_server_.VerifyRequestedOrigins({});
   image_compression_server_.VerifyRequestedImagePaths({});
   VerifyImageCompressionPageInfoState(false);
 }
@@ -389,13 +387,17 @@
   RetryForHistogramUntilCountReached(
       &histogram_tester_, "SubresourceRedirect.RobotsRulesFetcher.ResponseCode",
       1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult",
       SubresourceRedirectResult::kIneligibleRobotsTimeout, 1);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths({});
 
   using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad;
@@ -442,10 +444,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 2);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
   VerifyImageCompressionPageInfoState(true);
@@ -468,10 +474,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 2);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 2);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png", "/load_image/image.png?foo"});
   VerifyImageCompressionPageInfoState(true);
@@ -496,8 +506,10 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
 
@@ -542,8 +554,10 @@
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
 
@@ -569,7 +583,9 @@
       "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 2);
 
   // Another robots rules fetch happened.
-  VerifyRobotsRulesFetch(
+  histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 2);
+  robots_rules_server_.VerifyRequestedOrigins(
       {GetHttpsTestURL("/").spec(),
        https_test_server_.GetURL("differentorigin.com", "/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
@@ -666,6 +682,10 @@
   NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html"));
 
   // Robots rules fetch was success.
+  histogram_tester_.ExpectUniqueSample(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1);
 
@@ -687,7 +707,7 @@
   histogram_tester_.ExpectBucketCount(
       "SubresourceRedirect.LitePagesService.BypassResult", false, 2);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
 
@@ -707,10 +727,12 @@
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1);
+  histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 1);
   EXPECT_TRUE(RunScriptExtractBool("checkImage()"));
 
   // No more additional fetches.
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
   VerifyImageCompressionPageInfoState(true);
@@ -755,9 +777,13 @@
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
   histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
+  histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
+  histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({});
+  robots_rules_server_.VerifyRequestedOrigins({});
   image_compression_server_.VerifyRequestedImagePaths({});
   VerifyImageCompressionPageInfoState(false);
 }
@@ -787,10 +813,14 @@
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 2);
   // The robots rules are fetched once, since both images are from the same
   // origin.
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png?mainframe", "/load_image/image.png"});
   VerifyImageCompressionPageInfoState(true);
@@ -825,11 +855,16 @@
       net::HTTP_TEMPORARY_REDIRECT, 2);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 2);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 2);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 2);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec(),
-                          https_test_server_.GetURL("foo.com", "/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins(
+      {GetHttpsTestURL("/").spec(),
+       https_test_server_.GetURL("foo.com", "/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png?mainframe", "/load_image/image.png"});
   VerifyImageCompressionPageInfoState(true);
@@ -869,10 +904,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png?mainframe"});
   // Main frame still enables image compression.
@@ -905,9 +944,13 @@
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
   histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
+  histogram_tester_.ExpectTotalCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
+  histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({});
+  robots_rules_server_.VerifyRequestedOrigins({});
   image_compression_server_.VerifyRequestedImagePaths({});
   VerifyImageCompressionPageInfoState(false);
 }
@@ -985,6 +1028,10 @@
   RetryForHistogramUntilCountReached(
       &histogram_tester_, "SubresourceRedirect.RobotsRulesFetcher.ResponseCode",
       1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
   histogram_tester_.ExpectTotalCount(
@@ -996,7 +1043,7 @@
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths({});
 
   // Now start loading the image.
@@ -1017,10 +1064,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
 }
@@ -1080,9 +1131,13 @@
     histogram_tester_.ExpectTotalCount(
         "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
     histogram_tester_.ExpectTotalCount(
+        "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
+    histogram_tester_.ExpectTotalCount(
+        "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
+    histogram_tester_.ExpectTotalCount(
         "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-    VerifyRobotsRulesFetch({});
+    robots_rules_server_.VerifyRequestedOrigins({});
     image_compression_server_.VerifyRequestedImagePaths({});
     VerifyImageCompressionPageInfoState(false);
     return;
@@ -1098,10 +1153,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectUniqueSample(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png"});
 
@@ -1171,10 +1230,14 @@
       net::HTTP_TEMPORARY_REDIRECT, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.CompressionAttempt.ServerResponded", 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1);
+  histogram_tester_.ExpectBucketCount(
+      "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
   histogram_tester_.ExpectTotalCount(
       "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
 
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
+  robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()});
   image_compression_server_.VerifyRequestedImagePaths(
       {"/load_image/image.png?foo"});
   VerifyImageCompressionPageInfoState(true);
@@ -1243,8 +1306,11 @@
         net::HTTP_TEMPORARY_REDIRECT, 1);
     histogram_tester_.ExpectUniqueSample(
         "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1);
+    histogram_tester_.ExpectUniqueSample(
+        "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1);
 
-    VerifyRobotsRulesFetch({image_url.GetWithEmptyPath().spec()});
+    robots_rules_server_.VerifyRequestedOrigins(
+        {image_url.GetWithEmptyPath().spec()});
     image_compression_server_.VerifyRequestedImagePaths(
         {"/load_image/image.png"});
   } else {
@@ -1254,8 +1320,12 @@
         "SubresourceRedirect.CompressionAttempt.ResponseCode", 0);
     histogram_tester_.ExpectTotalCount(
         "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
+    histogram_tester_.ExpectTotalCount(
+        "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0);
+    histogram_tester_.ExpectTotalCount(
+        "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0);
 
-    VerifyRobotsRulesFetch({});
+    robots_rules_server_.VerifyRequestedOrigins({});
     image_compression_server_.VerifyRequestedImagePaths({});
   }
   histogram_tester_.ExpectTotalCount(
@@ -1296,115 +1366,4 @@
     testing::Combine(testing::Bool() /* allow_javascript_crossorigin_images */,
                      testing::Bool() /* is_crossorigin_image */));
 
-// Disables the actual subresource redirect and enables only recording metrics.
-class SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest
-    : public SubresourceRedirectLoginRobotsBrowserTest {
- public:
-  SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest()
-      : SubresourceRedirectLoginRobotsBrowserTest(
-            {{"enable_subresource_server_redirect", "false"}},
-            true, /* enable_lite_mode */
-            true  /* enable_login_robots_compression_feature */
-        ) {}
-};
-
-IN_PROC_BROWSER_TEST_F(
-    SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS(TestImageAllowedByRobots)) {
-  CreateUkmRecorder();
-  robots_rules_server_.AddRobotsRules(
-      GetHttpsTestURL("/"),
-      {{kRuleTypeAllow, "/load_image/image.png"}, {kRuleTypeDisallow, ""}});
-  NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html"));
-
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
-
-  // The image will start redirect and pause when robots rules are getting
-  // fetched. But there will not be an actual redirect.
-  histogram_tester_.ExpectUniqueSample(
-      "SubresourceRedirect.CompressionAttempt.ResponseCode",
-      net::HTTP_TEMPORARY_REDIRECT, 1);
-  histogram_tester_.ExpectUniqueSample(
-      "SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult",
-      SubresourceRedirectResult::kIneligibleCompressionDisabled, 1);
-  histogram_tester_.ExpectTotalCount(
-      "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
-  histogram_tester_.ExpectTotalCount(
-      "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
-  image_compression_server_.VerifyRequestedImagePaths({});
-
-  // Image load UKM should get recorded.
-  using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad;
-  auto ukm_metrics = GetImageCompressionUkmMetrics();
-  EXPECT_LT(100U, ukm_metrics[ImageCompressionUkm::kOriginalBytesNameHash]);
-  EXPECT_THAT(ukm_metrics,
-              testing::Not(testing::Contains(testing::Key(
-                  ImageCompressionUkm::kCompressionPercentageNameHash))));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kNavigationToRequestStartNameHash)));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kNavigationToRequestSentNameHash)));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kNavigationToResponseReceivedNameHash)));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kRobotsRulesFetchLatencyNameHash)));
-  EXPECT_EQ(SubresourceRedirectResult::kIneligibleCompressionDisabled,
-            static_cast<SubresourceRedirectResult>(
-                ukm_metrics[ImageCompressionUkm::kRedirectResultNameHash]));
-  VerifyImageCompressionPageInfoState(false);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS(TestImageDisallowedByRobots)) {
-  CreateUkmRecorder();
-  robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"),
-                                      {{kRuleTypeDisallow, ""}});
-  NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html"));
-
-  VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()});
-
-  // The image will start redirect and pause when robots rules are getting
-  // fetched. But there will not be an actual redirect.
-  histogram_tester_.ExpectUniqueSample(
-      "SubresourceRedirect.CompressionAttempt.ResponseCode",
-      net::HTTP_TEMPORARY_REDIRECT, 1);
-  histogram_tester_.ExpectUniqueSample(
-      "SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult",
-      SubresourceRedirectResult::kIneligibleRobotsDisallowed, 1);
-  histogram_tester_.ExpectTotalCount(
-      "SubresourceRedirect.CompressionAttempt.ServerResponded", 0);
-  histogram_tester_.ExpectTotalCount(
-      "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0);
-  image_compression_server_.VerifyRequestedImagePaths({});
-
-  // Image load UKM should get recorded.
-  using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad;
-  auto ukm_metrics = GetImageCompressionUkmMetrics();
-  EXPECT_LT(100U, ukm_metrics[ImageCompressionUkm::kOriginalBytesNameHash]);
-  EXPECT_THAT(ukm_metrics,
-              testing::Not(testing::Contains(testing::Key(
-                  ImageCompressionUkm::kCompressionPercentageNameHash))));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kNavigationToRequestStartNameHash)));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kNavigationToRequestSentNameHash)));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kNavigationToResponseReceivedNameHash)));
-  EXPECT_THAT(ukm_metrics,
-              testing::Contains(testing::Key(
-                  ImageCompressionUkm::kRobotsRulesFetchLatencyNameHash)));
-  EXPECT_EQ(SubresourceRedirectResult::kIneligibleRobotsDisallowed,
-            static_cast<SubresourceRedirectResult>(
-                ukm_metrics[ImageCompressionUkm::kRedirectResultNameHash]));
-  VerifyImageCompressionPageInfoState(false);
-}
-
 }  // namespace subresource_redirect
diff --git a/chrome/browser/extensions/activity_log/activity_actions.cc b/chrome/browser/extensions/activity_log/activity_actions.cc
index 82c8996..17524ad8 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.cc
+++ b/chrome/browser/extensions/activity_log/activity_actions.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/dom_action_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 
 namespace constants = activity_log_constants;
@@ -202,10 +203,9 @@
     std::string extra;
     if (other()->GetStringWithoutPathExpansion(constants::kActionExtra, &extra))
       other_field->extra = std::make_unique<std::string>(extra);
-    int dom_verb;
-    if (other()->GetIntegerWithoutPathExpansion(constants::kActionDomVerb,
-                                                &dom_verb)) {
-      switch (static_cast<DomActionType::Type>(dom_verb)) {
+    if (absl::optional<int> dom_verb =
+            other()->FindIntKey(constants::kActionDomVerb)) {
+      switch (static_cast<DomActionType::Type>(dom_verb.value())) {
         case DomActionType::GETTER:
           other_field->dom_verb =
               activity_log::EXTENSION_ACTIVITY_DOM_VERB_GETTER;
diff --git a/chrome/browser/extensions/back_forward_cache_browsertest.cc b/chrome/browser/extensions/back_forward_cache_browsertest.cc
index 7139fa3..e7b7ed2b 100644
--- a/chrome/browser/extensions/back_forward_cache_browsertest.cc
+++ b/chrome/browser/extensions/back_forward_cache_browsertest.cc
@@ -139,15 +139,9 @@
 }
 
 // Test content script injection disallow the back forward cache.
-// TODO(https://crbug.com/1204751): Very flaky on Windows.
-#if defined(OS_WIN)
-#define MAYBE_ScriptDisallowed DISABLED_ScriptDisallowed
-#else
-#define MAYBE_ScriptDisallowed ScriptDisallowed
-#endif
 IN_PROC_BROWSER_TEST_F(
     ExtensionBackForwardCacheContentScriptDisabledBrowserTest,
-    MAYBE_ScriptDisallowed) {
+    ScriptDisallowed) {
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("back_forward_cache")
                                 .AppendASCII("content_script")));
 
diff --git a/chrome/browser/extensions/extension_unload_browsertest.cc b/chrome/browser/extensions/extension_unload_browsertest.cc
index 177c390..7e64b01 100644
--- a/chrome/browser/extensions/extension_unload_browsertest.cc
+++ b/chrome/browser/extensions/extension_unload_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include "base/feature_list.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
diff --git a/chrome/browser/extensions/updater/extension_updater.h b/chrome/browser/extensions/updater/extension_updater.h
index 0597794..76648987 100644
--- a/chrome/browser/extensions/updater/extension_updater.h
+++ b/chrome/browser/extensions/updater/extension_updater.h
@@ -16,7 +16,6 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/extension_registry_observer.h"
diff --git a/chrome/browser/extensions/wake_event_page_apitest.cc b/chrome/browser/extensions/wake_event_page_apitest.cc
index 5cad30cca..395c299 100644
--- a/chrome/browser/extensions/wake_event_page_apitest.cc
+++ b/chrome/browser/extensions/wake_event_page_apitest.cc
@@ -7,7 +7,6 @@
 #include "base/auto_reset.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
diff --git a/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc b/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
index 0010dcf..6ed0ea4 100644
--- a/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler_browsertest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/scoped_observer.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 8751505..3454267 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3099,17 +3099,17 @@
   },
   {
     "name": "help-app-discover-tab",
-    "owners": [ "//ash/content/help_app_ui/OWNERS" ],
+    "owners": [ "//chromeos/components/help_app_ui/OWNERS" ],
     "expiry_milestone": 97
   },
   {
     "name": "help-app-launcher-search",
-    "owners": [ "//ash/content/help_app_ui/OWNERS" ],
+    "owners": [ "//chromeos/components/help_app_ui/OWNERS" ],
     "expiry_milestone": 97
   },
   {
     "name": "help-app-search-service-integration",
-    "owners": [ "//ash/content/help_app_ui/OWNERS" ],
+    "owners": [ "//chromeos/components/help_app_ui/OWNERS" ],
     "expiry_milestone": 94
   },
   {
@@ -4463,12 +4463,12 @@
   },
   {
     "name": "release-notes-notification",
-    "owners": [ "//ash/content/help_app_ui/OWNERS" ],
+    "owners": [ "//chromeos/components/help_app_ui/OWNERS" ],
     "expiry_milestone": 90
   },
   {
     "name": "release-notes-notification-all-channels",
-    "owners": [ "//ash/content/help_app_ui/OWNERS" ],
+    "owners": [ "//chromeos/components/help_app_ui/OWNERS" ],
     // This is required by test teams to verify functionality on dev/beta
     // channels on devices which have no access to commandline flags.
     "expiry_milestone": -1
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 762e84b..435cd37 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -112,6 +112,7 @@
     &features::kQuietNotificationPrompts,
     &features::kRequestDesktopSiteForTablets,
     &features::kSearchHistoryLink,
+    &features::kShareUsageRanking,
     &features::kToolbarUseHardwareBitmapDraw,
     &features::kUseNotificationCompatBuilder,
     &features::kWebNfc,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index ee127d2..050c56d 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -446,6 +446,7 @@
             "ServiceManagerForBackgroundPrefetch";
     public static final String SERVICE_MANAGER_FOR_DOWNLOAD = "ServiceManagerForDownload";
     public static final String SHARE_BUTTON_IN_TOP_TOOLBAR = "ShareButtonInTopToolbar";
+    public static final String SHARE_USAGE_RANKING = "ShareUsageRanking";
     public static final String SHARED_CLIPBOARD_UI = "SharedClipboardUI";
     public static final String SHARED_HIGHLIGHTING_V2 = "SharedHighlightingV2";
     public static final String SHOW_TRUSTED_PUBLISHER_URL = "ShowTrustedPublisherURL";
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
index 060db47..652c4cb 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -17,7 +17,6 @@
 #include "base/containers/flat_map.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
diff --git a/chrome/browser/notifications/notification_platform_bridge_delegator.h b/chrome/browser/notifications/notification_platform_bridge_delegator.h
index 03fb21bc..42d0e95b 100644
--- a/chrome/browser/notifications/notification_platform_bridge_delegator.h
+++ b/chrome/browser/notifications/notification_platform_bridge_delegator.h
@@ -11,7 +11,6 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/notifications/displayed_notifications_dispatch_callback.h"
 #include "chrome/browser/notifications/notification_common.h"
 #include "chrome/browser/notifications/notification_handler.h"
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc
index bcd044e..08f2a6ba 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc
@@ -466,8 +466,15 @@
   EXPECT_EQ(0, ratio_bucket);
 }
 
+
+// Flaky on linux-chromeos-rel. crbug/1215539
+#if defined(NDEBUG) && defined(OS_CHROMEOS)
+#define MAYBE_AlwaysInBackground DISABLED_AlwaysInBackground
+#else
+#define MAYBE_AlwaysInBackground AlwaysInBackground
+#endif
 IN_PROC_BROWSER_TEST_F(HttpsEngagementPageLoadMetricsBrowserTest,
-                       AlwaysInBackground) {
+                       MAYBE_AlwaysInBackground) {
   StartHttpsServer(false);
   StartHttpServer();
   NavigateInBackgroundAndClose(https_test_server_->GetURL("/simple.html"));
diff --git a/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc b/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
index 34c1851..7b281fc 100644
--- a/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
+++ b/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
@@ -8,7 +8,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/scoped_observer.h"
 #include "base/values.h"
 #include "chrome/browser/password_manager/android/password_infobar_utils.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index d8f01476..c66bf99 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -329,7 +329,7 @@
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.h"
 #include "chrome/browser/chromeos/policy/dm_token_storage.h"
 #include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h"
-#include "chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data/handlers/device_wallpaper_image_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/policy/reporting/app_install_event_log_manager_wrapper.h"
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
index 8ad0b71..20c6185 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
@@ -7,7 +7,6 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_source_base.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index d62b010..a226f4a7 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -106,6 +106,7 @@
     if (is_linux || is_chromeos || is_win || is_mac) {
       deps += [
         "bluetooth_internals:closure_compile",
+        "bookmarks:closure_compile",
         "commander:closure_compile",
         "discards:closure_compile",
         "download_internals:closure_compile",
diff --git a/chrome/browser/resources/bookmarks/BUILD.gn b/chrome/browser/resources/bookmarks/BUILD.gn
index 3f11bd5b..dd8bd076 100644
--- a/chrome/browser/resources/bookmarks/BUILD.gn
+++ b/chrome/browser/resources/bookmarks/BUILD.gn
@@ -3,15 +3,14 @@
 # found in the LICENSE file.
 
 import("//chrome/common/features.gni")
+import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
-import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
-tsc_folder = "tsc"
 preprocess_manifest = "preprocessed_manifest.json"
 preprocess_gen_manifest = "preprocessed_gen_manifest.json"
 
@@ -20,13 +19,14 @@
 
   optimize_webui("build") {
     host = "bookmarks"
-    input = rebase_path("$target_gen_dir/$tsc_folder", root_build_dir)
+    input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir)
     js_out_files = [ "bookmarks.rollup.js" ]
     js_module_in_files = [ "bookmarks.js" ]
     out_manifest = "$target_gen_dir/$build_manifest"
 
     deps = [
-      ":build_ts",
+      ":preprocess",
+      ":preprocess_generated",
       "../../../../ui/webui/resources:preprocess",
     ]
     excludes = [ "chrome://resources/js/cr.m.js" ]
@@ -42,8 +42,14 @@
     manifest_files = [ "$target_gen_dir/$build_manifest" ]
     resource_path_rewrites = [ "bookmarks.rollup.js|bookmarks.js" ]
   } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+    deps = [
+      ":preprocess",
+      ":preprocess_generated",
+    ]
+    manifest_files = [
+      "$target_gen_dir/$preprocess_manifest",
+      "$target_gen_dir/$preprocess_gen_manifest",
+    ]
   }
   grd_prefix = "bookmarks"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
@@ -54,20 +60,20 @@
   out_folder = "$target_gen_dir/$preprocess_folder"
   out_manifest = "$target_gen_dir/$preprocess_manifest"
   in_files = [
-    "actions.ts",
-    "api_listener.ts",
-    "bookmarks.ts",
-    "browser_proxy.ts",
-    "constants.ts",
-    "debouncer.ts",
-    "dialog_focus_manager.ts",
-    "dnd_manager.ts",
-    "mouse_focus_behavior.ts",
-    "reducers.ts",
-    "store_client.ts",
-    "store.ts",
-    "types.ts",
-    "util.ts",
+    "actions.js",
+    "api_listener.js",
+    "bookmarks.js",
+    "browser_proxy.js",
+    "constants.js",
+    "debouncer.js",
+    "dialog_focus_manager.js",
+    "dnd_manager.js",
+    "mouse_focus_behavior.js",
+    "reducers.js",
+    "store_client.js",
+    "store.js",
+    "types.js",
+    "util.js",
   ]
 }
 
@@ -77,31 +83,31 @@
   out_folder = "$target_gen_dir/$preprocess_folder"
   out_manifest = "$target_gen_dir/$preprocess_gen_manifest"
   in_files = [
-    "app.ts",
-    "command_manager.ts",
-    "edit_dialog.ts",
-    "folder_node.ts",
-    "item.ts",
-    "list.ts",
-    "router.ts",
-    "shared_style.ts",
-    "shared_vars.ts",
-    "toolbar.ts",
+    "app.js",
+    "command_manager.js",
+    "edit_dialog.js",
+    "folder_node.js",
+    "item.js",
+    "list.js",
+    "router.js",
+    "shared_style.js",
+    "shared_vars.js",
+    "toolbar.js",
   ]
 }
 
 html_to_js("web_components") {
   js_files = [
-    "app.ts",
-    "command_manager.ts",
-    "edit_dialog.ts",
-    "folder_node.ts",
-    "item.ts",
-    "list.ts",
-    "router.ts",
-    "shared_style.ts",
-    "shared_vars.ts",
-    "toolbar.ts",
+    "app.js",
+    "command_manager.js",
+    "edit_dialog.js",
+    "folder_node.js",
+    "item.js",
+    "list.js",
+    "router.js",
+    "shared_style.js",
+    "shared_vars.js",
+    "toolbar.js",
   ]
 }
 
@@ -122,51 +128,261 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-ts_library("build_ts") {
-  root_dir = "$target_gen_dir/$preprocess_folder"
-  out_dir = "$target_gen_dir/$tsc_folder"
-  tsconfig_base = "tsconfig_base.json"
-  in_files = [
-    "actions.ts",
-    "api_listener.ts",
-    "app.ts",
-    "bookmarks.ts",
-    "browser_proxy.ts",
-    "command_manager.ts",
-    "constants.ts",
-    "debouncer.ts",
-    "dialog_focus_manager.ts",
-    "dnd_manager.ts",
-    "edit_dialog.ts",
-    "folder_node.ts",
-    "item.ts",
-    "list.ts",
-    "mouse_focus_behavior.ts",
-    "reducers.ts",
-    "router.ts",
-    "shared_vars.ts",
-    "shared_style.ts",
-    "store.ts",
-    "store_client.ts",
-    "toolbar.ts",
-    "types.ts",
-    "util.ts",
-  ]
-  definitions = [
-    "//tools/typescript/definitions/bookmark_manager_private.d.ts",
-    "//tools/typescript/definitions/bookmarks.d.ts",
-    "//tools/typescript/definitions/chrome_event.d.ts",
-    "//tools/typescript/definitions/chrome_send.d.ts",
-    "//tools/typescript/definitions/metrics_private.d.ts",
-    "//tools/typescript/definitions/tabs.d.ts",
-    "//tools/typescript/definitions/windows.d.ts",
-  ]
+js_type_check("closure_compile") {
+  is_polymer3 = true
   deps = [
-    "//third_party/polymer/v3_0:library",
-    "//ui/webui/resources:library",
+    ":actions",
+    ":api_listener",
+    ":app",
+    ":browser_proxy",
+    ":command_manager",
+    ":constants",
+    ":debouncer",
+    ":dialog_focus_manager",
+    ":dnd_manager",
+    ":edit_dialog",
+    ":folder_node",
+    ":item",
+    ":list",
+    ":mouse_focus_behavior",
+    ":reducers",
+    ":router",
+    ":store",
+    ":store_client",
+    ":toolbar",
+    ":types",
+    ":util",
   ]
-  extra_deps = [
-    ":preprocess",
-    ":preprocess_generated",
+}
+
+js_library("actions") {
+  deps = [
+    ":types",
+    ":util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr/ui:store.m",
   ]
+
+  externs_list = [ "$externs_path/bookmarks.js" ]
+}
+
+js_library("api_listener") {
+  deps = [
+    ":actions",
+    ":browser_proxy",
+    ":constants",
+    ":debouncer",
+    ":store",
+    ":util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr/ui:store.m",
+  ]
+
+  externs_list = [ "$externs_path/bookmarks.js" ]
+}
+
+js_library("app") {
+  deps = [
+    ":api_listener",
+    ":dnd_manager",
+    ":mouse_focus_behavior",
+    ":router",
+    ":store",
+    ":store_client",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements:find_shortcut_behavior",
+    "//ui/webui/resources/cr_elements/cr_splitter:cr_splitter",
+    "//ui/webui/resources/js:load_time_data.m",
+  ]
+  externs_list = [
+    "$externs_path/bookmarks.js",
+    "$externs_path/metrics_private.js",
+  ]
+}
+
+js_library("browser_proxy") {
+  deps = [
+    ":constants",
+    "//ui/webui/resources/js:cr.m",
+  ]
+}
+
+js_library("command_manager") {
+  deps = [
+    ":actions",
+    ":api_listener",
+    ":browser_proxy",
+    ":dialog_focus_manager",
+    ":edit_dialog",
+    ":store_client",
+    ":types",
+    ":util",
+    "//third_party/polymer/v3_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m",
+    "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render.m",
+    "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager.m",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:load_time_data.m",
+    "//ui/webui/resources/js:plural_string_proxy",
+    "//ui/webui/resources/js/cr/ui:keyboard_shortcut_list.m",
+  ]
+  externs_list = chrome_extension_public_externs + [
+                   "$externs_path/bookmark_manager_private.js",
+                   "$externs_path/bookmarks.js",
+                 ]
+}
+
+js_library("constants") {
+}
+
+js_library("debouncer") {
+  deps = [
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:promise_resolver.m",
+  ]
+}
+
+js_library("dialog_focus_manager") {
+  deps = [ "//ui/webui/resources/js:cr.m" ]
+}
+
+js_library("dnd_manager") {
+  deps = [
+    ":api_listener",
+    ":debouncer",
+    ":folder_node",
+    ":store",
+    ":types",
+    ":util",
+  ]
+  externs_list = [
+    "$externs_path/bookmark_manager_private.js",
+    "$externs_path/metrics_private.js",
+  ]
+}
+
+js_library("edit_dialog") {
+  deps = [
+    ":api_listener",
+    ":dialog_focus_manager",
+    ":types",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+    "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:load_time_data.m",
+  ]
+  externs_list = [ "$externs_path/bookmarks.js" ]
+}
+
+js_library("folder_node") {
+  deps = [
+    ":actions",
+    ":command_manager",
+    ":constants",
+    ":store_client",
+    ":types",
+    ":util",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:util.m",
+  ]
+}
+
+js_library("item") {
+  deps = [
+    ":actions",
+    ":browser_proxy",
+    ":command_manager",
+    ":constants",
+    ":store_client",
+    ":types",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:icon.m",
+    "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
+  ]
+}
+
+js_library("list") {
+  deps = [
+    ":actions",
+    ":command_manager",
+    ":constants",
+    ":item",
+    ":store_client",
+    ":types",
+    ":util",
+    "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:list_property_update_behavior.m",
+    "//ui/webui/resources/js:load_time_data.m",
+    "//ui/webui/resources/js:plural_string_proxy",
+  ]
+}
+
+js_library("mouse_focus_behavior") {
+}
+
+js_library("reducers") {
+  deps = [
+    ":actions",
+    ":types",
+    "//ui/webui/resources/js:assert.m",
+  ]
+}
+
+js_library("router") {
+  deps = [
+    ":actions",
+    ":constants",
+    ":store_client",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_library("store") {
+  deps = [
+    ":reducers",
+    ":types",
+    ":util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr/ui:store.m",
+  ]
+}
+
+js_library("store_client") {
+  deps = [
+    ":store",
+    ":types",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr/ui:store_client.m",
+  ]
+}
+
+js_library("toolbar") {
+  deps = [
+    ":command_manager",
+    ":constants",
+    ":edit_dialog",
+    ":store_client",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m",
+    "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar",
+    "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:load_time_data.m",
+  ]
+}
+
+js_library("types") {
+  deps = [ ":constants" ]
+  externs_list = [ "$externs_path/bookmarks.js" ]
+}
+
+js_library("util") {
+  deps = [ ":types" ]
+
+  externs_list = [ "$externs_path/bookmarks.js" ]
 }
diff --git a/chrome/browser/resources/bookmarks/actions.js b/chrome/browser/resources/bookmarks/actions.js
new file mode 100644
index 0000000..a45cd123
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/actions.js
@@ -0,0 +1,275 @@
+// Copyright 2017 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 {assert} from 'chrome://resources/js/assert.m.js';
+import {Action} from 'chrome://resources/js/cr/ui/store.m.js';
+
+import {IncognitoAvailability, ROOT_NODE_ID} from './constants.js';
+import {BookmarksPageState, NodeMap} from './types.js';
+import {getDescendants, getDisplayedList, normalizeNode} from './util.js';
+
+/**
+ * @fileoverview Module for functions which produce action objects. These are
+ * listed in one place to document available actions and their parameters.
+ */
+
+/**
+ * @param {string} id
+ * @param {chrome.bookmarks.BookmarkTreeNode} treeNode
+ */
+export function createBookmark(id, treeNode) {
+  return {
+    name: 'create-bookmark',
+    id: id,
+    parentId: treeNode.parentId,
+    parentIndex: treeNode.index,
+    node: normalizeNode(treeNode),
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {{title: string, url: (string|undefined)}} changeInfo
+ * @return {!Action}
+ */
+export function editBookmark(id, changeInfo) {
+  return {
+    name: 'edit-bookmark',
+    id: id,
+    changeInfo: changeInfo,
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {string} parentId
+ * @param {number} index
+ * @param {string} oldParentId
+ * @param {number} oldIndex
+ * @return {!Action}
+ */
+export function moveBookmark(id, parentId, index, oldParentId, oldIndex) {
+  return {
+    name: 'move-bookmark',
+    id: id,
+    parentId: parentId,
+    index: index,
+    oldParentId: oldParentId,
+    oldIndex: oldIndex,
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {!Array<string>} newChildIds
+ */
+export function reorderChildren(id, newChildIds) {
+  return {
+    name: 'reorder-children',
+    id: id,
+    children: newChildIds,
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {string} parentId
+ * @param {number} index
+ * @param {NodeMap} nodes
+ * @return {!Action}
+ */
+export function removeBookmark(id, parentId, index, nodes) {
+  const descendants = getDescendants(nodes, id);
+  return {
+    name: 'remove-bookmark',
+    id: id,
+    descendants: descendants,
+    parentId: parentId,
+    index: index,
+  };
+}
+
+/**
+ * @param {NodeMap} nodeMap
+ * @return {!Action}
+ */
+export function refreshNodes(nodeMap) {
+  return {
+    name: 'refresh-nodes',
+    nodes: nodeMap,
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {NodeMap} nodes Current node state. Can be omitted in tests.
+ * @return {?Action}
+ */
+export function selectFolder(id, nodes) {
+  if (nodes && (id === ROOT_NODE_ID || !nodes[id] || nodes[id].url)) {
+    console.warn('Tried to select invalid folder: ' + id);
+    return null;
+  }
+
+  return {
+    name: 'select-folder',
+    id: id,
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {boolean} open
+ * @return {!Action}
+ */
+export function changeFolderOpen(id, open) {
+  return {
+    name: 'change-folder-open',
+    id: id,
+    open: open,
+  };
+}
+
+/** @return {!Action} */
+export function clearSearch() {
+  return {
+    name: 'clear-search',
+  };
+}
+
+/** @return {!Action} */
+export function deselectItems() {
+  return {
+    name: 'deselect-items',
+  };
+}
+
+/**
+ * @param {string} id
+ * @param {BookmarksPageState} state
+ * @param {{
+ *     clear: boolean,
+ *     range: boolean,
+ *     toggle: boolean}} config Options for how the selection should change:
+ *   - clear: If true, clears the previous selection before adding this one
+ *   - range: If true, selects all items from the anchor to this item
+ *   - toggle: If true, toggles the selection state of the item. Cannot be
+ *     used with clear or range.
+ * @return {!Action}
+ */
+export function selectItem(id, state, config) {
+  assert(!config.toggle || !config.range);
+  assert(!config.toggle || !config.clear);
+
+  const anchor = state.selection.anchor;
+  const toSelect = [];
+  let newAnchor = id;
+
+  if (config.range && anchor) {
+    const displayedList = getDisplayedList(state);
+    const selectedIndex = displayedList.indexOf(id);
+    assert(selectedIndex !== -1);
+    let anchorIndex = displayedList.indexOf(anchor);
+    if (anchorIndex === -1) {
+      anchorIndex = selectedIndex;
+    }
+
+    // When performing a range selection, don't change the anchor from what
+    // was used in this selection.
+    newAnchor = displayedList[anchorIndex];
+
+    const startIndex = Math.min(anchorIndex, selectedIndex);
+    const endIndex = Math.max(anchorIndex, selectedIndex);
+
+    for (let i = startIndex; i <= endIndex; i++) {
+      toSelect.push(displayedList[i]);
+    }
+  } else {
+    toSelect.push(id);
+  }
+
+  return {
+    name: 'select-items',
+    clear: config.clear,
+    toggle: config.toggle,
+    anchor: newAnchor,
+    items: toSelect,
+  };
+}
+
+/**
+ * @param {Array<string>} ids
+ * @param {BookmarksPageState} state
+ * @param {string=} anchor
+ * @return {!Action}
+ */
+export function selectAll(ids, state, anchor) {
+  return {
+    name: 'select-items',
+    clear: true,
+    toggle: false,
+    anchor: anchor ? anchor : state.selection.anchor,
+    items: ids,
+  };
+}
+
+/**
+ * @param {string} id
+ * @return {!Action}
+ */
+export function updateAnchor(id) {
+  return {
+    name: 'update-anchor',
+    anchor: id,
+  };
+}
+
+/**
+ * @param {string} term
+ * @return {!Action}
+ */
+export function setSearchTerm(term) {
+  if (!term) {
+    return clearSearch();
+  }
+
+  return {
+    name: 'start-search',
+    term: term,
+  };
+}
+
+/**
+ * @param {!Array<string>} ids
+ * @return {!Action}
+ */
+export function setSearchResults(ids) {
+  return {
+    name: 'finish-search',
+    results: ids,
+  };
+}
+
+/**
+ * @param {IncognitoAvailability} availability
+ * @return {!Action}
+ */
+export function setIncognitoAvailability(availability) {
+  assert(availability !== IncognitoAvailability.FORCED);
+  return {
+    name: 'set-incognito-availability',
+    value: availability,
+  };
+}
+
+/**
+ * @param {boolean} canEdit
+ * @return {!Action}
+ */
+export function setCanEditBookmarks(canEdit) {
+  return {
+    name: 'set-can-edit',
+    value: canEdit,
+  };
+}
diff --git a/chrome/browser/resources/bookmarks/actions.ts b/chrome/browser/resources/bookmarks/actions.ts
deleted file mode 100644
index 6e56829..0000000
--- a/chrome/browser/resources/bookmarks/actions.ts
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright 2017 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 {assert} from 'chrome://resources/js/assert.m.js';
-import {Action} from 'chrome://resources/js/cr/ui/store.m.js';
-
-import {IncognitoAvailability, ROOT_NODE_ID} from './constants.js';
-import {BookmarkNode, BookmarksPageState, NodeMap} from './types.js';
-import {getDescendants, getDisplayedList, normalizeNode} from './util.js';
-
-/**
- * @fileoverview Module for functions which produce action objects. These are
- * listed in one place to document available actions and their parameters.
- */
-
-export class CreateBookmarkAction extends Action {
-  id: string;
-  parentId: string;
-  parentIndex: number;
-  node: BookmarkNode;
-}
-
-export function createBookmark(
-    id: string,
-    treeNode: chrome.bookmarks.BookmarkTreeNode): CreateBookmarkAction {
-  return {
-    name: 'create-bookmark',
-    id: id,
-    parentId: treeNode.parentId!,
-    parentIndex: treeNode.index!,
-    node: normalizeNode(treeNode),
-  };
-}
-
-export class EditBookmarkAction extends Action {
-  id: string;
-  changeInfo: {title: string, url?: string};
-}
-
-export function editBookmark(
-    id: string, changeInfo: {title: string, url?: string}): EditBookmarkAction {
-  return {
-    name: 'edit-bookmark',
-    id: id,
-    changeInfo: changeInfo,
-  };
-}
-
-export class MoveBookmarkAction extends Action {
-  id: string;
-  parentId: string;
-  index: number;
-  oldParentId: string;
-  oldIndex: number;
-}
-
-export function moveBookmark(
-    id: string, parentId: string, index: number, oldParentId: string,
-    oldIndex: number): MoveBookmarkAction {
-  return {
-    name: 'move-bookmark',
-    id: id,
-    parentId: parentId,
-    index: index,
-    oldParentId: oldParentId,
-    oldIndex: oldIndex,
-  };
-}
-
-export class ReorderChildrenAction extends Action {
-  id: string;
-  children: string[];
-}
-
-export function reorderChildren(
-    id: string, newChildIds: string[]): ReorderChildrenAction {
-  return {
-    name: 'reorder-children',
-    id: id,
-    children: newChildIds,
-  };
-}
-
-export class RemoveBookmarkAction extends Action {
-  id: string;
-  parentId: string;
-  index: number;
-  descendants: Set<string>;
-}
-
-export function removeBookmark(
-    id: string, parentId: string, index: number,
-    nodes: NodeMap): RemoveBookmarkAction {
-  const descendants = getDescendants(nodes, id);
-  return {
-    name: 'remove-bookmark',
-    id: id,
-    descendants: descendants,
-    parentId: parentId,
-    index: index,
-  };
-}
-
-export class RefreshNodesAction extends Action {
-  nodes: NodeMap;
-}
-
-export function refreshNodes(nodeMap: NodeMap): RefreshNodesAction {
-  return {
-    name: 'refresh-nodes',
-    nodes: nodeMap,
-  };
-}
-
-export class SelectFolderAction extends Action {
-  id: string;
-}
-
-export function selectFolder(
-    id: string, nodes: NodeMap): SelectFolderAction|null {
-  if (nodes && (id === ROOT_NODE_ID || !nodes[id] || nodes[id]!.url)) {
-    console.warn('Tried to select invalid folder: ' + id);
-    return null;
-  }
-
-  return {
-    name: 'select-folder',
-    id: id,
-  };
-}
-
-export class ChangeFolderOpenAction extends Action {
-  id: string;
-  open: boolean;
-}
-
-export function changeFolderOpen(
-    id: string, open: boolean): ChangeFolderOpenAction {
-  return {
-    name: 'change-folder-open',
-    id: id,
-    open: open,
-  };
-}
-
-export function clearSearch(): Action {
-  return {
-    name: 'clear-search',
-  };
-}
-
-export function deselectItems(): Action {
-  return {
-    name: 'deselect-items',
-  };
-}
-
-export class SelectItemsAction extends Action {
-  clear: boolean;
-  toggle: boolean;
-  anchor: string;
-  items: string[];
-}
-
-export function selectItem(
-    id: string, state: BookmarksPageState,
-    config: {clear: boolean, range: boolean, toggle: boolean}):
-    SelectItemsAction {
-  assert(!config.toggle || !config.range);
-  assert(!config.toggle || !config.clear);
-
-  const anchor = state.selection.anchor;
-  const toSelect: string[] = [];
-  let newAnchor = id;
-
-  if (config.range && anchor) {
-    const displayedList = getDisplayedList(state);
-    const selectedIndex = displayedList.indexOf(id);
-    assert(selectedIndex !== -1);
-    let anchorIndex = displayedList.indexOf(anchor);
-    if (anchorIndex === -1) {
-      anchorIndex = selectedIndex;
-    }
-
-    // When performing a range selection, don't change the anchor from what
-    // was used in this selection.
-    newAnchor = displayedList[anchorIndex]!;
-
-    const startIndex = Math.min(anchorIndex, selectedIndex);
-    const endIndex = Math.max(anchorIndex, selectedIndex);
-
-    for (let i = startIndex; i <= endIndex; i++) {
-      toSelect.push(displayedList[i]!);
-    }
-  } else {
-    toSelect.push(id);
-  }
-
-  return {
-    name: 'select-items',
-    clear: config.clear,
-    toggle: config.toggle,
-    anchor: newAnchor,
-    items: toSelect,
-  };
-}
-
-export function selectAll(
-    ids: string[], state: BookmarksPageState,
-    anchor?: string): SelectItemsAction {
-  const finalAnchor: string = anchor ? anchor! : state.selection!.anchor!;
-  return {
-    name: 'select-items',
-    clear: true,
-    toggle: false,
-    anchor: finalAnchor,
-    items: ids,
-  };
-}
-
-export class UpdateAnchorAction extends Action {
-  anchor: string;
-}
-
-export function updateAnchor(id: string): UpdateAnchorAction {
-  return {
-    name: 'update-anchor',
-    anchor: id,
-  };
-}
-
-export class StartSearchAction extends Action {
-  term: string;
-}
-
-export function setSearchTerm(term: string): (Action|StartSearchAction) {
-  if (!term) {
-    return clearSearch();
-  }
-
-  return {
-    name: 'start-search',
-    term: term,
-  };
-}
-
-export class FinishSearchAction extends Action {
-  results: string[];
-}
-
-export function setSearchResults(ids: string[]): Action {
-  return {
-    name: 'finish-search',
-    results: ids,
-  } as Action;
-}
-
-export class SetPrefAction extends Action {
-  value: IncognitoAvailability|boolean;
-}
-
-export function setIncognitoAvailability(availability: IncognitoAvailability):
-    SetPrefAction {
-  assert(availability !== IncognitoAvailability.FORCED);
-  return {
-    name: 'set-incognito-availability',
-    value: availability,
-  };
-}
-
-export function setCanEditBookmarks(canEdit: boolean): SetPrefAction {
-  return {
-    name: 'set-can-edit',
-    value: canEdit,
-  };
-}
diff --git a/chrome/browser/resources/bookmarks/api_listener.ts b/chrome/browser/resources/bookmarks/api_listener.js
similarity index 67%
rename from chrome/browser/resources/bookmarks/api_listener.ts
rename to chrome/browser/resources/bookmarks/api_listener.js
index 8581e3b..1372390 100644
--- a/chrome/browser/resources/bookmarks/api_listener.ts
+++ b/chrome/browser/resources/bookmarks/api_listener.js
@@ -18,10 +18,12 @@
  * chrome.bookmarks API into actions to modify the local page state.
  */
 
-let trackUpdates: boolean = false;
-let updatedItems: string[] = [];
+/** @type {boolean} */
+let trackUpdates = false;
+/** @type {!Array<string>} */
+let updatedItems = [];
 
-let debouncer: Debouncer;
+let debouncer;
 
 /**
  * Batches UI updates so that no changes will be made to UI until the next
@@ -72,17 +74,24 @@
   debouncer.promise.then(highlightUpdatedItemsImpl);
 }
 
-function dispatch(action: Action) {
+/** @param {Action} action */
+function dispatch(action) {
   Store.getInstance().dispatch(action);
 }
 
-function onBookmarkChanged(
-    id: string, changeInfo: chrome.bookmarks.ChangeInfo) {
+/**
+ * @param {string} id
+ * @param {{title: string, url: (string|undefined)}} changeInfo
+ */
+function onBookmarkChanged(id, changeInfo) {
   dispatch(editBookmark(id, changeInfo));
 }
 
-function onBookmarkCreated(
-    id: string, treeNode: chrome.bookmarks.BookmarkTreeNode) {
+/**
+ * @param {string} id
+ * @param {chrome.bookmarks.BookmarkTreeNode} treeNode
+ */
+function onBookmarkCreated(id, treeNode) {
   batchUIUpdates();
   if (trackUpdates) {
     updatedItems.push(id);
@@ -90,14 +99,26 @@
   dispatch(createBookmark(id, treeNode));
 }
 
-function onBookmarkRemoved(
-    id: string, removeInfo: chrome.bookmarks.RemoveInfo) {
+/**
+ * @param {string} id
+ * @param {{parentId: string, index: number}} removeInfo
+ */
+function onBookmarkRemoved(id, removeInfo) {
   batchUIUpdates();
   const nodes = Store.getInstance().data.nodes;
   dispatch(removeBookmark(id, removeInfo.parentId, removeInfo.index, nodes));
 }
 
-function onBookmarkMoved(id: string, moveInfo: chrome.bookmarks.MoveInfo) {
+/**
+ * @param {string} id
+ * @param {{
+ *    parentId: string,
+ *    index: number,
+ *    oldParentId: string,
+ *    oldIndex: number
+ * }} moveInfo
+ */
+function onBookmarkMoved(id, moveInfo) {
   batchUIUpdates();
   if (trackUpdates) {
     updatedItems.push(id);
@@ -107,8 +128,11 @@
       moveInfo.oldIndex));
 }
 
-function onChildrenReordered(
-    id: string, reorderInfo: chrome.bookmarks.ReorderInfo) {
+/**
+ * @param {string} id
+ * @param {{childIds: !Array<string>}} reorderInfo
+ */
+function onChildrenReordered(id, reorderInfo) {
   dispatch(reorderChildren(id, reorderInfo.childIds));
 }
 
@@ -122,31 +146,43 @@
 
 function onImportEnded() {
   chrome.bookmarks.getTree(function(results) {
-    dispatch(refreshNodes(normalizeNodes(results[0]!)));
+    dispatch(refreshNodes(normalizeNodes(results[0])));
   });
   chrome.bookmarks.onCreated.addListener(onBookmarkCreated);
 }
 
-function onIncognitoAvailabilityChanged(availability: IncognitoAvailability) {
+/**
+ * @param {IncognitoAvailability} availability
+ */
+function onIncognitoAvailabilityChanged(availability) {
   dispatch(setIncognitoAvailability(availability));
 }
 
-function onCanEditBookmarksChanged(canEdit: boolean) {
+/**
+ * @param {boolean} canEdit
+ */
+function onCanEditBookmarksChanged(canEdit) {
   dispatch(setCanEditBookmarks(canEdit));
 }
 
-let incognitoAvailabilityListener: {eventName: string, uid: number}|null = null;
+const listeners = [
+  {api: chrome.bookmarks.onChanged, fn: onBookmarkChanged},
+  {api: chrome.bookmarks.onChildrenReordered, fn: onChildrenReordered},
+  {api: chrome.bookmarks.onCreated, fn: onBookmarkCreated},
+  {api: chrome.bookmarks.onMoved, fn: onBookmarkMoved},
+  {api: chrome.bookmarks.onRemoved, fn: onBookmarkRemoved},
+  {api: chrome.bookmarks.onImportBegan, fn: onImportBegan},
+  {api: chrome.bookmarks.onImportEnded, fn: onImportEnded},
+];
 
-let canEditBookmarksListener: {eventName: string, uid: number}|null = null;
+/** @type {?{eventName: string, uid: number}} */
+let incognitoAvailabilityListener = null;
+
+/** @type {?{eventName: string, uid: number}} */
+let canEditBookmarksListener = null;
 
 export function init() {
-  chrome.bookmarks.onChanged.addListener(onBookmarkChanged);
-  chrome.bookmarks.onChildrenReordered.addListener(onChildrenReordered);
-  chrome.bookmarks.onCreated.addListener(onBookmarkCreated);
-  chrome.bookmarks.onMoved.addListener(onBookmarkMoved);
-  chrome.bookmarks.onRemoved.addListener(onBookmarkRemoved);
-  chrome.bookmarks.onImportBegan.addListener(onImportBegan);
-  chrome.bookmarks.onImportEnded.addListener(onImportEnded);
+  listeners.forEach((listener) => listener.api.addListener(listener.fn));
 
   const browserProxy = BrowserProxy.getInstance();
   browserProxy.getIncognitoAvailability().then(onIncognitoAvailabilityChanged);
@@ -159,13 +195,7 @@
 }
 
 export function destroy() {
-  chrome.bookmarks.onChanged.removeListener(onBookmarkChanged);
-  chrome.bookmarks.onChildrenReordered.removeListener(onChildrenReordered);
-  chrome.bookmarks.onCreated.removeListener(onBookmarkCreated);
-  chrome.bookmarks.onMoved.removeListener(onBookmarkMoved);
-  chrome.bookmarks.onRemoved.removeListener(onBookmarkRemoved);
-  chrome.bookmarks.onImportBegan.removeListener(onImportBegan);
-  chrome.bookmarks.onImportEnded.removeListener(onImportEnded);
+  listeners.forEach((listener) => listener.api.removeListener(listener.fn));
   if (incognitoAvailabilityListener) {
     removeWebUIListener(/** @type {{eventName: string, uid: number}} */ (
         incognitoAvailabilityListener));
diff --git a/chrome/browser/resources/bookmarks/app.ts b/chrome/browser/resources/bookmarks/app.js
similarity index 67%
rename from chrome/browser/resources/bookmarks/app.ts
rename to chrome/browser/resources/bookmarks/app.js
index a1b5c0b..9204c8c 100644
--- a/chrome/browser/resources/bookmarks/app.ts
+++ b/chrome/browser/resources/bookmarks/app.js
@@ -13,12 +13,10 @@
 import './shared_vars.js';
 import './strings.m.js';
 import './command_manager.js';
-import './toolbar.js';
 
-import {CrSplitterElement} from 'chrome://resources/cr_elements/cr_splitter/cr_splitter.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.m.js';
-import {FindShortcutBehavior} from 'chrome://resources/cr_elements/find_shortcut_behavior.js';
+import {FindShortcutBehavior, FindShortcutBehaviorInterface} from 'chrome://resources/cr_elements/find_shortcut_behavior.js';
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -26,57 +24,62 @@
 import {destroy as destroyApiListener, init as initApiListener} from './api_listener.js';
 import {LOCAL_STORAGE_FOLDER_STATE_KEY, LOCAL_STORAGE_TREE_WIDTH_KEY, ROOT_NODE_ID} from './constants.js';
 import {DNDManager} from './dnd_manager.js';
-import {MouseFocusMixin} from './mouse_focus_behavior.js';
+import {MouseFocusBehavior} from './mouse_focus_behavior.js';
 import {Store} from './store.js';
 import {BookmarksStoreClientInterface, StoreClient} from './store_client.js';
 import {BookmarksToolbarElement} from './toolbar.js';
 import {BookmarksPageState, FolderOpenState} from './types.js';
 import {createEmptyState, normalizeNodes} from './util.js';
 
-const BookmarksAppElementBase =
-    mixinBehaviors([StoreClient, FindShortcutBehavior],
-                   MouseFocusMixin(PolymerElement)) as {
-  new (): PolymerElement & BookmarksStoreClientInterface &
-      StoreObserver<BookmarksPageState> & FindShortcutBehavior
-}
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ * @implements {FindShortcutBehaviorInterface}
+ */
+const BookmarksAppElementBase = mixinBehaviors(
+    [StoreClient, MouseFocusBehavior, FindShortcutBehavior], PolymerElement);
 
-export interface BookmarksAppElement {
-  $: {
-    splitter: CrSplitterElement,
-    sidebar: HTMLDivElement,
-  }
-}
-
+/** @polymer */
 export class BookmarksAppElement extends BookmarksAppElementBase {
   static get is() {
     return 'bookmarks-app';
   }
 
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
   static get properties() {
     return {
+      /** @private */
       searchTerm_: {
         type: String,
         observer: 'searchTermChanged_',
       },
 
+      /** @type {FolderOpenState} */
       folderOpenState_: {
         type: Object,
         observer: 'folderOpenStateChanged_',
       },
 
+      /** @private */
       sidebarWidth_: String,
     };
   }
 
-  private eventTracker_: EventTracker = new EventTracker();
-  private dndManager_: DNDManager|null = null;
-  private folderOpenState_: FolderOpenState;
-  private searchTerm_: string;
-  private sidebarWidth_: string;
-
   constructor() {
     super();
 
+    /** @private{?function(!Event)} */
+    this.boundUpdateSidebarWidth_ = null;
+
+    /** @private {DNDManager} */
+    this.dndManager_ = null;
+
     // Regular expression that captures the leading slash, the content and the
     // trailing slash in three different groups.
     const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
@@ -86,28 +89,31 @@
     }
   }
 
+  /** @override */
   connectedCallback() {
     super.connectedCallback();
 
     document.documentElement.classList.remove('loading');
 
-    this.watch('searchTerm_', function(state: BookmarksPageState) {
+    this.watch('searchTerm_', function(state) {
       return state.search.term;
     });
 
-    this.watch('folderOpenState_', function(state: BookmarksPageState) {
+    this.watch('folderOpenState_', function(state) {
       return state.folderOpenState;
     });
 
     chrome.bookmarks.getTree((results) => {
-      const nodeMap = normalizeNodes(results[0]!);
+      const nodeMap = normalizeNodes(results[0]);
       const initialState = createEmptyState();
       initialState.nodes = nodeMap;
-      initialState.selectedFolder = nodeMap[ROOT_NODE_ID]!.children![0]!;
+      initialState.selectedFolder = nodeMap[ROOT_NODE_ID].children[0];
       const folderStateString =
           window.localStorage[LOCAL_STORAGE_FOLDER_STATE_KEY];
       initialState.folderOpenState = folderStateString ?
-          new Map(JSON.parse(folderStateString)) :
+          new Map(
+              /** @type Array<Array<boolean|string>> */ (
+                  JSON.parse(folderStateString))) :
           new Map();
 
       Store.getInstance().init(initialState);
@@ -120,6 +126,8 @@
       });
     });
 
+    this.boundUpdateSidebarWidth_ = this.updateSidebarWidth_.bind(this);
+
     this.initializeSplitter_();
 
     this.dndManager_ = new DNDManager();
@@ -129,12 +137,16 @@
   disconnectedCallback() {
     super.disconnectedCallback();
 
-    this.eventTracker_.remove(window, 'resize');
-    this.dndManager_!.destroy();
+    window.removeEventListener('resize', this.boundUpdateSidebarWidth_);
+    this.dndManager_.destroy();
     destroyApiListener();
   }
 
-  private initializeSplitter_(): void {
+  /**
+   * Set up the splitter and set the initial width from localStorage.
+   * @private
+   */
+  initializeSplitter_() {
     const splitter = this.$.splitter;
     const splitterTarget = this.$.sidebar;
 
@@ -143,7 +155,8 @@
       splitterTarget.style.width =
           window.localStorage[LOCAL_STORAGE_TREE_WIDTH_KEY];
     }
-    this.sidebarWidth_ = getComputedStyle(splitterTarget).width;
+    this.sidebarWidth_ =
+        /** @type {string} */ (getComputedStyle(splitterTarget).width);
 
     splitter.addEventListener('resize', (e) => {
       window.localStorage[LOCAL_STORAGE_TREE_WIDTH_KEY] =
@@ -151,16 +164,18 @@
       this.updateSidebarWidth_();
     });
 
-    this.eventTracker_.add(splitter, 'dragmove',
-                           () => this.updateSidebarWidth_());
-    this.eventTracker_.add(window, 'resize', () => this.updateSidebarWidth_());
+    splitter.addEventListener('dragmove', this.boundUpdateSidebarWidth_);
+    window.addEventListener('resize', this.boundUpdateSidebarWidth_);
   }
 
-  private updateSidebarWidth_(): void {
-    this.sidebarWidth_ = getComputedStyle(this.$.sidebar).width;
+  /** @private */
+  updateSidebarWidth_() {
+    this.sidebarWidth_ =
+        /** @type {string} */ (getComputedStyle(this.$.sidebar).width);
   }
 
-  private searchTermChanged_(newValue: string, oldValue?: string) {
+  /** @private */
+  searchTermChanged_(newValue, oldValue) {
     if (oldValue !== undefined && !newValue) {
       this.dispatchEvent(new CustomEvent('iron-announce', {
         bubbles: true,
@@ -190,35 +205,37 @@
     });
   }
 
-  private folderOpenStateChanged_(): void {
+  /** @private */
+  folderOpenStateChanged_() {
     window.localStorage[LOCAL_STORAGE_FOLDER_STATE_KEY] =
         JSON.stringify(Array.from(this.folderOpenState_));
   }
 
   // Override FindShortcutBehavior methods.
-  handleFindShortcut(modalContextOpen: boolean): boolean {
+  /** @override */
+  handleFindShortcut(modalContextOpen) {
     if (modalContextOpen) {
       return false;
     }
-    this.shadowRoot!.querySelector<BookmarksToolbarElement>(
-        'bookmarks-toolbar')!.searchField.showAndFocus();
+    /** @type {!BookmarksToolbarElement} */ (
+        this.shadowRoot.querySelector('bookmarks-toolbar'))
+        .searchField.showAndFocus();
     return true;
   }
 
   // Override FindShortcutBehavior methods.
-  searchInputHasFocus(): boolean {
-    return this.shadowRoot!.querySelector<BookmarksToolbarElement>(
-        'bookmarks-toolbar')!.searchField.isSearchFocused();
+  /** @override */
+  searchInputHasFocus() {
+    return /** @type {!BookmarksToolbarElement} */ (
+               this.shadowRoot.querySelector('bookmarks-toolbar'))
+        .searchField.isSearchFocused();
   }
 
-  private onUndoClick_(): void {
+  /** @private */
+  onUndoClick_() {
     this.dispatchEvent(
         new CustomEvent('command-undo', {bubbles: true, composed: true}));
   }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
 }
 
 customElements.define(BookmarksAppElement.is, BookmarksAppElement);
diff --git a/chrome/browser/resources/bookmarks/bookmarks.ts b/chrome/browser/resources/bookmarks/bookmarks.js
similarity index 100%
rename from chrome/browser/resources/bookmarks/bookmarks.ts
rename to chrome/browser/resources/bookmarks/bookmarks.js
diff --git a/chrome/browser/resources/bookmarks/browser_proxy.js b/chrome/browser/resources/bookmarks/browser_proxy.js
new file mode 100644
index 0000000..8d615c99
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/browser_proxy.js
@@ -0,0 +1,49 @@
+// Copyright 2019 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 {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+
+import {IncognitoAvailability} from './constants.js';
+
+export class BrowserProxy {
+  /**
+   * @return {!Promise<!IncognitoAvailability>} Promise resolved with the
+   *     current incognito mode preference.
+   */
+  getIncognitoAvailability() {
+    return sendWithPromise('getIncognitoAvailability');
+  }
+
+  /**
+   * @return {!Promise<boolean>} Promise resolved with whether the bookmarks
+   *     can be edited.
+   */
+  getCanEditBookmarks() {
+    return sendWithPromise('getCanEditBookmarks');
+  }
+
+  /**
+   * Notifies the metrics handler to record a histogram value.
+   * @param {string} histogram The name of the histogram to record
+   * @param {number} bucket The bucket to record
+   * @param {number} maxBucket The maximum bucket value in the histogram.
+   */
+  recordInHistogram(histogram, bucket, maxBucket) {
+    chrome.send(
+        'metricsHandler:recordInHistogram', [histogram, bucket, maxBucket]);
+  }
+
+  /** @return {!BrowserProxy} */
+  static getInstance() {
+    return instance || (instance = new BrowserProxy());
+  }
+
+  /** @param {!BrowserProxy} obj */
+  static setInstance(obj) {
+    instance = obj;
+  }
+}
+
+/** @type {?BrowserProxy} */
+let instance = null;
diff --git a/chrome/browser/resources/bookmarks/browser_proxy.ts b/chrome/browser/resources/bookmarks/browser_proxy.ts
deleted file mode 100644
index 2f794df..0000000
--- a/chrome/browser/resources/bookmarks/browser_proxy.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2019 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 {sendWithPromise} from 'chrome://resources/js/cr.m.js';
-
-import {IncognitoAvailability} from './constants.js';
-
-export class BrowserProxy {
-  getIncognitoAvailability(): Promise<IncognitoAvailability> {
-    return sendWithPromise('getIncognitoAvailability');
-  }
-
-  getCanEditBookmarks(): Promise<boolean> {
-    return sendWithPromise('getCanEditBookmarks');
-  }
-
-  recordInHistogram(histogram: string, bucket: number, maxBucket: number) {
-    chrome.send(
-        'metricsHandler:recordInHistogram', [histogram, bucket, maxBucket]);
-  }
-
-  static getInstance(): BrowserProxy {
-    return instance || (instance = new BrowserProxy());
-  }
-
-  static setInstance(obj: BrowserProxy) {
-    instance = obj;
-  }
-}
-
-let instance: BrowserProxy|null = null;
diff --git a/chrome/browser/resources/bookmarks/command_manager.ts b/chrome/browser/resources/bookmarks/command_manager.js
similarity index 72%
rename from chrome/browser/resources/bookmarks/command_manager.ts
rename to chrome/browser/resources/bookmarks/command_manager.js
index ae441676..f47e1c0 100644
--- a/chrome/browser/resources/bookmarks/command_manager.ts
+++ b/chrome/browser/resources/bookmarks/command_manager.js
@@ -7,7 +7,6 @@
  * shortcuts.
  */
 import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.m.js';
-import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
@@ -15,17 +14,13 @@
 import './edit_dialog.js';
 import './shared_style.js';
 import './strings.m.js';
-import './edit_dialog.js';
 
-import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.m.js';
-import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
-import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.m.js';
 import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
 import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
 import {isMac} from 'chrome://resources/js/cr.m.js';
 import {KeyboardShortcutList} from 'chrome://resources/js/cr/ui/keyboard_shortcut_list.m.js';
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
@@ -38,25 +33,23 @@
 import {DialogFocusManager} from './dialog_focus_manager.js';
 import {BookmarksEditDialogElement} from './edit_dialog.js';
 import {BookmarksStoreClientInterface, StoreClient} from './store_client.js';
-import {BookmarkNode, BookmarksPageState, OpenCommandMenuDetail} from './types.js';
+import {BookmarkNode, BookmarksPageState} from './types.js';
 import {canEditNode, canReorderChildren, getDisplayedList} from './util.js';
 
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ */
 const BookmarksCommandManagerElementBase =
-    mixinBehaviors([StoreClient], PolymerElement) as {
-  new (): PolymerElement & BookmarksStoreClientInterface &
-          StoreObserver<BookmarksPageState>
-}
+    mixinBehaviors([StoreClient], PolymerElement);
 
-export interface BookmarksCommandManagerElement {
-  $: {
-    dropdown: CrLazyRenderElement,
-    editDialog: CrLazyRenderElement,
-    openDialog: CrLazyRenderElement,
-  }
-}
+/** @type {?BookmarksCommandManagerElement} */
+let instance = null;
 
-let instance: BookmarksCommandManagerElement|null = null;
-
+/** @polymer */
 export class BookmarksCommandManagerElement extends
     BookmarksCommandManagerElementBase {
   static get is() {
@@ -69,47 +62,52 @@
 
   static get properties() {
     return {
+      /** @private {!Array<Command>} */
       menuCommands_: {
         type: Array,
         computed: 'computeMenuCommands_(menuSource_)',
       },
 
+      /** @private {Set<string>} */
       menuIds_: Object,
 
-      menuSource_: Number,
+      /**
+       * Indicates where the context menu was opened from. Will be NONE if
+       * menu is not open, indicating that commands are from keyboard shortcuts
+       * or elsewhere in the UI.
+       * @private {MenuSource}
+       */
+      menuSource_: {
+        type: Number,
+        value: MenuSource.NONE,
+      },
 
+      /** @private */
       canPaste_: Boolean,
 
+      /** @private */
       globalCanEdit_: Boolean,
     };
   }
 
-  /**
-   * Indicates where the context menu was opened from. Will be NONE if
-   * menu is not open, indicating that commands are from keyboard shortcuts
-   * or elsewhere in the UI.
-   */
-  private menuSource_: MenuSource = MenuSource.NONE;
-  private confirmOpenCallback_: (() => void)|null = null;
-  private canPaste_: boolean;
-  private globalCanEdit_: boolean;
-  private menuIds_: Set<string>;
-  private menuCommands_: Command[];
-  private browserProxy_: BrowserProxy;
-  private shortcuts_: Map<Command, KeyboardShortcutList>;
-  private eventTracker_: EventTracker = new EventTracker();
+  constructor() {
+    super();
+    /** @private {?Function} */
+    this.confirmOpenCallback_ = null;
+  }
 
   connectedCallback() {
     super.connectedCallback();
     assert(instance === null);
     instance = this;
 
+    /** @private {!BrowserProxy} */
     this.browserProxy_ = BrowserProxy.getInstance();
 
-    this.watch(
-        'globalCanEdit_', state => (state as BookmarksPageState).prefs.canEdit);
+    this.watch('globalCanEdit_', state => state.prefs.canEdit);
     this.updateFromStore();
 
+    /** @private {!Map<Command, KeyboardShortcutList>} */
     this.shortcuts_ = new Map();
 
     this.addShortcut_(Command.EDIT, 'F2', 'Enter');
@@ -132,16 +130,21 @@
     this.addShortcut_(Command.COPY, 'Ctrl|c', 'Meta|c');
     this.addShortcut_(Command.PASTE, 'Ctrl|v', 'Meta|v');
 
-    this.eventTracker_.add(document, 'open-command-menu', e =>
-                           this.onOpenCommandMenu_(
-                               e as CustomEvent<OpenCommandMenuDetail>));
-    this.eventTracker_.add(document, 'keydown', e =>
-                           this.onKeydown_(e as KeyboardEvent));
+    /** @private {!Map<string, Function>} */
+    this.boundListeners_ = new Map();
 
-    const addDocumentListenerForCommand = (eventName: string,
-                                           command: Command) => {
-      this.eventTracker_.add(document, eventName, e => {
-        if ((e.composedPath()[0] as HTMLElement).tagName === 'INPUT') {
+    const addDocumentListener = (eventName, handler) => {
+      assert(!this.boundListeners_.has(eventName));
+      const boundListener = handler.bind(this);
+      this.boundListeners_.set(eventName, boundListener);
+      document.addEventListener(eventName, boundListener);
+    };
+    addDocumentListener('open-command-menu', this.onOpenCommandMenu_);
+    addDocumentListener('keydown', this.onKeydown_);
+
+    const addDocumentListenerForCommand = (eventName, command) => {
+      addDocumentListener(eventName, (e) => {
+        if (e.path[0].tagName === 'INPUT') {
           return;
         }
 
@@ -164,20 +167,26 @@
   disconnectedCallback() {
     super.disconnectedCallback();
     instance = null;
-    this.eventTracker_.removeAll();
+    this.boundListeners_.forEach(
+        (handler, eventName) =>
+            document.removeEventListener(eventName, handler));
   }
 
   /**
    * Display the command context menu at (|x|, |y|) in window coordinates.
    * Commands will execute on |items| if given, or on the currently selected
    * items.
+   * @param {number} x
+   * @param {number} y
+   * @param {MenuSource} source
+   * @param {Set<string>=} items
    */
-  openCommandMenuAtPosition(
-      x: number, y: number, source: MenuSource, items?: Set<string>) {
+  openCommandMenuAtPosition(x, y, source, items) {
     this.menuSource_ = source;
     this.menuIds_ = items || this.getState().selection.items;
 
-    const dropdown = (this.$.dropdown.get()) as CrActionMenuElement;
+    const dropdown =
+        /** @type {!CrActionMenuElement} */ (this.$.dropdown.get());
     // Ensure that the menu is fully rendered before trying to position it.
     flush();
     DialogFocusManager.getInstance().showDialog(
@@ -189,12 +198,15 @@
   /**
    * Display the command context menu positioned to cover the |target|
    * element. Commands will execute on the currently selected items.
+   * @param {!Element} target
+   * @param {MenuSource} source
    */
-  openCommandMenuAtElement(target: Element, source: MenuSource) {
+  openCommandMenuAtElement(target, source) {
     this.menuSource_ = source;
     this.menuIds_ = this.getState().selection.items;
 
-    const dropdown = this.$.dropdown.get() as CrActionMenuElement;
+    const dropdown =
+        /** @type {!CrActionMenuElement} */ (this.$.dropdown.get());
     // Ensure that the menu is fully rendered before trying to position it.
     flush();
     DialogFocusManager.getInstance().showDialog(
@@ -206,7 +218,7 @@
   closeCommandMenu() {
     this.menuIds_ = new Set();
     this.menuSource_ = MenuSource.NONE;
-    (this.$.dropdown.get() as CrActionMenuElement).close();
+    /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()).close();
   }
 
   ////////////////////////////////////////////////////////////////////////////
@@ -216,8 +228,11 @@
    * Determine if the |command| can be executed with the given |itemIds|.
    * Commands which appear in the context menu should be implemented
    * separately using `isCommandVisible_` and `isCommandEnabled_`.
+   * @param {Command} command
+   * @param {!Set<string>} itemIds
+   * @return {boolean}
    */
-  canExecute(command: Command, itemIds: Set<string>): boolean {
+  canExecute(command, itemIds) {
     const state = this.getState();
     switch (command) {
       case Command.OPEN:
@@ -244,7 +259,13 @@
     }
   }
 
-  isCommandVisible_(command: Command, itemIds: Set<string>): boolean {
+  /**
+   * @param {Command} command
+   * @param {!Set<string>} itemIds
+   * @return {boolean} True if the command should be visible in the context
+   *     menu.
+   */
+  isCommandVisible_(command, itemIds) {
     switch (command) {
       case Command.EDIT:
         return itemIds.size === 1 && this.globalCanEdit_;
@@ -278,7 +299,13 @@
     return assert(false);
   }
 
-  private isCommandEnabled_(command: Command, itemIds: Set<string>): boolean {
+  /**
+   * @param {Command} command
+   * @param {!Set<string>} itemIds
+   * @return {boolean} True if the command should be clickable in the context
+   *     menu.
+   */
+  isCommandEnabled_(command, itemIds) {
     const state = this.getState();
     switch (command) {
       case Command.EDIT:
@@ -295,7 +322,7 @@
             IncognitoAvailability.DISABLED;
       case Command.SORT:
         return this.canChangeList_() &&
-            state.nodes[state.selectedFolder]!.children!.length > 1;
+            state.nodes[state.selectedFolder].children.length > 1;
       case Command.ADD_BOOKMARK:
       case Command.ADD_FOLDER:
         return this.canChangeList_();
@@ -310,27 +337,33 @@
 
   /**
    * Returns whether the currently displayed bookmarks list can be changed.
+   * @private
+   * @return {boolean}
    */
-  private canChangeList_(): boolean {
+  canChangeList_() {
     const state = this.getState();
     return state.search.term === '' &&
         canReorderChildren(state, state.selectedFolder);
   }
 
-  handle(command: Command, itemIds: Set<string>) {
+  /**
+   * @param {Command} command
+   * @param {!Set<string>} itemIds
+   */
+  handle(command, itemIds) {
     const state = this.getState();
     switch (command) {
       case Command.EDIT: {
-        const id = Array.from(itemIds)[0]!;
-        (this.$.editDialog.get() as BookmarksEditDialogElement)
-            .showEditDialog(state.nodes[id]!);
+        const id = Array.from(itemIds)[0];
+        /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
+            .showEditDialog(state.nodes[id]);
         break;
       }
       case Command.COPY_URL:
       case Command.COPY: {
         const idList = Array.from(itemIds);
         chrome.bookmarkManagerPrivate.copy(idList, () => {
-          let labelPromise: Promise<string>;
+          let labelPromise;
           if (command === Command.COPY_URL) {
             labelPromise =
                 Promise.resolve(loadTimeData.getString('toastUrlCopied'));
@@ -343,14 +376,14 @@
           }
 
           this.showTitleToast_(
-              labelPromise, state.nodes[idList[0]!]!.title, false);
+              labelPromise, state.nodes[idList[0]].title, false);
         });
         break;
       }
       case Command.SHOW_IN_FOLDER: {
         const id = Array.from(itemIds)[0];
         this.dispatch(
-            selectFolder(assert(state.nodes[id!]!.parentId!), state.nodes));
+            selectFolder(assert(state.nodes[id].parentId), state.nodes));
         DialogFocusManager.getInstance().clearFocus();
         this.dispatchEvent(new CustomEvent(
             'highlight-items', {bubbles: true, composed: true, detail: [id]}));
@@ -358,8 +391,8 @@
       }
       case Command.DELETE: {
         const idList = Array.from(this.minimizeDeletionSet_(itemIds));
-        const title = state.nodes[idList[0]!]!.title;
-        let labelPromise: Promise<string>;
+        const title = state.nodes[idList[0]].title;
+        let labelPromise;
 
         if (idList.length === 1) {
           labelPromise =
@@ -388,7 +421,7 @@
         break;
       case Command.OPEN:
         if (this.isFolder_(itemIds)) {
-          const folderId = Array.from(itemIds)[0]!;
+          const folderId = Array.from(itemIds)[0];
           this.dispatch(selectFolder(folderId, state.nodes));
         } else {
           this.openUrls_(this.expandUrls_(itemIds), command);
@@ -420,15 +453,15 @@
       case Command.SORT:
         chrome.bookmarkManagerPrivate.sortChildren(
             assert(state.selectedFolder));
-        getToastManager().querySelector('dom-if')!.if = true;
+        getToastManager().querySelector('dom-if').if = true;
         getToastManager().show(loadTimeData.getString('toastFolderSorted'));
         break;
       case Command.ADD_BOOKMARK:
-        (this.$.editDialog.get() as BookmarksEditDialogElement)
+        /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
             .showAddDialog(false, assert(state.selectedFolder));
         break;
       case Command.ADD_FOLDER:
-        (this.$.editDialog.get() as BookmarksEditDialogElement)
+        /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
             .showAddDialog(true, assert(state.selectedFolder));
         break;
       case Command.IMPORT:
@@ -447,10 +480,17 @@
         itemIds, 'BookmarkManager.CommandExecuted', command);
   }
 
-  handleKeyEvent(e: Event, itemIds: Set<string>): boolean {
+  /**
+   * @param {!Event} e
+   * @param {!Set<string>} itemIds
+   * @return {boolean} True if the event was handled, triggering a keyboard
+   *     shortcut.
+   */
+  handleKeyEvent(e, itemIds) {
     for (const commandTuple of this.shortcuts_) {
-      const command = commandTuple[0] as Command;
-      const shortcut = commandTuple[1] as KeyboardShortcutList;
+      const command = /** @type {Command} */ (commandTuple[0]);
+      const shortcut =
+          /** @type {KeyboardShortcutList} */ (commandTuple[1]);
       if (shortcut.matchesEvent(e) && this.canExecute(command, itemIds)) {
         this.handle(command, itemIds);
 
@@ -468,9 +508,13 @@
 
   /**
    * Register a keyboard shortcut for a command.
+   * @param {Command} command Command that the shortcut will trigger.
+   * @param {string} shortcut Keyboard shortcut, using the syntax of
+   *     cr/ui/command.js.
+   * @param {string=} macShortcut If set, enables a replacement shortcut for
+   *     Mac.
    */
-  private addShortcut_(
-      command: Command, shortcut: string, macShortcut?: string) {
+  addShortcut_(command, shortcut, macShortcut) {
     shortcut = (isMac && macShortcut) ? macShortcut : shortcut;
     this.shortcuts_.set(command, new KeyboardShortcutList(shortcut));
   }
@@ -481,14 +525,16 @@
    * both a node and its descendant, we will only try to delete the topmost
    * node, preventing an error in the bookmarkManagerPrivate.removeTrees API
    * call.
+   * @param {!Set<string>} itemIds
+   * @return {!Set<string>}
    */
-  private minimizeDeletionSet_(itemIds: Set<string>): Set<string> {
-    const minimizedSet = new Set() as Set<string>;
+  minimizeDeletionSet_(itemIds) {
+    const minimizedSet = new Set();
     const nodes = this.getState().nodes;
     itemIds.forEach(function(itemId) {
-      let currentId = itemId!;
+      let currentId = itemId;
       while (currentId !== ROOT_NODE_ID) {
-        currentId = assert(nodes[currentId]!.parentId!);
+        currentId = assert(nodes[currentId].parentId);
         if (itemIds.has(currentId)) {
           return;
         }
@@ -501,8 +547,11 @@
   /**
    * Open the given |urls| in response to a |command|. May show a confirmation
    * dialog before opening large numbers of URLs.
+   * @param {!Array<string>} urls
+   * @param {Command} command
+   * @private
    */
-  private openUrls_(urls: Array<string>, command: Command) {
+  openUrls_(urls, command) {
     assert(
         command === Command.OPEN || command === Command.OPEN_NEW_TAB ||
         command === Command.OPEN_NEW_WINDOW ||
@@ -533,11 +582,10 @@
 
     this.confirmOpenCallback_ = openUrlsCallback;
     const dialog = this.$.openDialog.get();
-    dialog.querySelector('[slot=body]')!.textContent =
+    dialog.querySelector('[slot=body]').textContent =
         loadTimeData.getStringF('openDialogBody', urls.length);
 
-    DialogFocusManager.getInstance().showDialog(
-        this.$.openDialog.get() as CrDialogElement);
+    DialogFocusManager.getInstance().showDialog(this.$.openDialog.get());
   }
 
   /**
@@ -545,18 +593,21 @@
    * Note that these will be ordered by insertion order into the |itemIds|
    * set, and that it is possible to duplicate a URL by passing in both the
    * parent ID and child ID.
+   * @param {!Set<string>} itemIds
+   * @return {!Array<string>}
+   * @private
    */
-  private expandUrls_(itemIds: Set<string>): string[] {
-    const urls: string[] = [];
+  expandUrls_(itemIds) {
+    const urls = [];
     const nodes = this.getState().nodes;
 
     itemIds.forEach(function(id) {
-      const node = nodes[id]!;
+      const node = nodes[id];
       if (node.url) {
         urls.push(node.url);
       } else {
-        node.children!.forEach(function(childId) {
-          const childNode = nodes[childId]!;
+        node.children.forEach(function(childId) {
+          const childNode = nodes[childId];
           if (childNode.url) {
             urls.push(childNode.url);
           }
@@ -567,28 +618,49 @@
     return urls;
   }
 
-  private containsMatchingNode_(
-      itemIds: Set<string>, predicate: (p1: BookmarkNode) => boolean): boolean {
+  /**
+   * @param {!Set<string>} itemIds
+   * @param {function(BookmarkNode):boolean} predicate
+   * @return {boolean} True if any node in |itemIds| returns true for
+   *     |predicate|.
+   */
+  containsMatchingNode_(itemIds, predicate) {
     const nodes = this.getState().nodes;
 
     return Array.from(itemIds).some(function(id) {
-      return predicate(nodes[id]!);
+      return predicate(nodes[id]);
     });
   }
 
-  private isSingleBookmark_(itemIds: Set<string>): boolean {
+  /**
+   * @param {!Set<string>} itemIds
+   * @return {boolean} True if |itemIds| is a single bookmark (non-folder)
+   *     node.
+   * @private
+   */
+  isSingleBookmark_(itemIds) {
     return itemIds.size === 1 &&
         this.containsMatchingNode_(itemIds, function(node) {
           return !!node.url;
         });
   }
 
-  private isFolder_(itemIds: Set<string>): boolean {
+  /**
+   * @param {!Set<string>} itemIds
+   * @return {boolean}
+   * @private
+   */
+  isFolder_(itemIds) {
     return itemIds.size === 1 &&
         this.containsMatchingNode_(itemIds, node => !node.url);
   }
 
-  private getCommandLabel_(command: Command): string {
+  /**
+   * @param {Command} command
+   * @return {string}
+   * @private
+   */
+  getCommandLabel_(command) {
     // Handle non-pluralized strings first.
     let label = null;
     switch (command) {
@@ -597,8 +669,8 @@
           return '';
         }
 
-        const id = Array.from(this.menuIds_)[0]!;
-        const itemUrl = this.getState().nodes[id]!.url;
+        const id = Array.from(this.menuIds_)[0];
+        const itemUrl = this.getState().nodes[id].url;
         label = itemUrl ? 'menuEdit' : 'menuRename';
         break;
       case Command.CUT:
@@ -662,8 +734,14 @@
     return '';
   }
 
-  private getPluralizedOpenAllString_(
-      case0: string, case1: string, caseOther: string): string {
+  /**
+   * @param {string} case0 String ID for the case of zero URLs.
+   * @param {string} case1 String ID for the case of 1 URL.
+   * @param {string} caseOther String ID for string that includes the URL count.
+   * @return {string}
+   * @private
+   */
+  getPluralizedOpenAllString_(case0, case1, caseOther) {
     const multipleNodes = this.menuIds_.size > 1 ||
         this.containsMatchingNode_(this.menuIds_, node => !node.url);
 
@@ -679,7 +757,12 @@
     return loadTimeData.getStringF(caseOther, urls.length);
   }
 
-  private getCommandSublabel_(command: Command): string {
+  /**
+   * @param {Command} command
+   * @return {string}
+   * @private
+   */
+  getCommandSublabel_(command) {
     const multipleNodes = this.menuIds_.size > 1 ||
         this.containsMatchingNode_(this.menuIds_, function(node) {
           return !node.url;
@@ -693,7 +776,8 @@
     }
   }
 
-  private computeMenuCommands_(): Command[] {
+  /** @private */
+  computeMenuCommands_() {
     switch (this.menuSource_) {
       case MenuSource.ITEM:
       case MenuSource.TREE:
@@ -732,10 +816,15 @@
         return [];
     }
     assert(false);
-    return [];
   }
 
-  private showDividerAfter_(command: Command, itemIds: Set<string>): boolean {
+  /**
+   * @param {Command} command
+   * @param {!Set<string>} itemIds
+   * @return {boolean}
+   * @private
+   */
+  showDividerAfter_(command, itemIds) {
     switch (command) {
       case Command.SORT:
       case Command.ADD_FOLDER:
@@ -749,8 +838,13 @@
     return false;
   }
 
-  private recordCommandHistogram_(
-      itemIds: Set<string>, histogram: string, command: number) {
+  /**
+   * @param {!Set<string>} itemIds
+   * @param {string} histogram
+   * @param {number} command
+   * @private
+   */
+  recordCommandHistogram_(itemIds, histogram, command) {
     if (command === Command.OPEN) {
       command =
           this.isFolder_(itemIds) ? Command.OPEN_FOLDER : Command.OPEN_BOOKMARK;
@@ -762,24 +856,29 @@
   /**
    * Show a toast with a bookmark |title| inserted into a label, with the
    * title ellipsised if necessary.
+   * @param {!Promise<string>} labelPromise Promise which resolves with the
+   *    label for the toast.
+   * @param {string} title Bookmark title to insert.
+   * @param {boolean} canUndo If true, shows an undo button in the toast.
+   * @private
    */
-  private async showTitleToast_(
-      labelPromise: Promise<string>, title: string,
-      canUndo: boolean): Promise<void> {
+  async showTitleToast_(labelPromise, title, canUndo) {
     const label = await labelPromise;
     const pieces =
         loadTimeData.getSubstitutedStringPieces(label, title).map(function(p) {
           // Make the bookmark name collapsible.
-          const result =
-              p as {value: string, arg: string, collapsible: boolean};
-          result.collapsible = !!p.arg;
-          return result;
+          p.collapsible = !!p.arg;
+          return p;
         });
-    getToastManager().querySelector('dom-if')!.if = canUndo;
+    getToastManager().querySelector('dom-if').if = canUndo;
     getToastManager().showForStringPieces(pieces);
   }
 
-  private updateCanPaste_(targetId: string): Promise<void> {
+  /**
+   * @param {number} targetId
+   * @private
+   */
+  updateCanPaste_(targetId) {
     return new Promise(resolve => {
       chrome.bookmarkManagerPrivate.canPaste(`${targetId}`, result => {
         this.canPaste_ = result;
@@ -791,37 +890,47 @@
   ////////////////////////////////////////////////////////////////////////////
   // Event handlers:
 
-  private async onOpenCommandMenu_(
-      e: CustomEvent<OpenCommandMenuDetail>): Promise<void> {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  async onOpenCommandMenu_(e) {
     if (e.detail.targetId) {
       await this.updateCanPaste_(e.detail.targetId);
     }
     if (e.detail.targetElement) {
-      this.openCommandMenuAtElement(e.detail.targetElement!, e.detail.source);
+      this.openCommandMenuAtElement(e.detail.targetElement, e.detail.source);
     } else {
-      this.openCommandMenuAtPosition(e.detail.x!, e.detail.y!, e.detail.source);
+      this.openCommandMenuAtPosition(e.detail.x, e.detail.y, e.detail.source);
     }
     this.browserProxy_.recordInHistogram(
         'BookmarkManager.CommandMenuOpened', e.detail.source,
         MenuSource.NUM_VALUES);
   }
 
-  private onCommandClick_(e: Event) {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onCommandClick_(e) {
     this.handle(
-        Number((e.currentTarget as HTMLElement).getAttribute('command')) as
-            Command,
+        /** @type {Command} */ (
+            Number(e.currentTarget.getAttribute('command'))),
         assert(this.menuIds_));
     this.closeCommandMenu();
   }
 
-  private onKeydown_(e: Event) {
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onKeydown_(e) {
     const path = e.composedPath();
-    if ((path[0] as HTMLElement).tagName === 'INPUT') {
+    if (path[0].tagName === 'INPUT') {
       return;
     }
     if ((e.target === document.body ||
-         path.some(
-             el => (el as HTMLElement).tagName === 'BOOKMARKS-TOOLBAR')) &&
+         path.some(el => el.tagName === 'BOOKMARKS-TOOLBAR')) &&
         !DialogFocusManager.getInstance().hasOpenDialog()) {
       this.handleKeyEvent(e, this.getState().selection.items);
     }
@@ -831,27 +940,31 @@
    * Close the menu on mousedown so clicks can propagate to the underlying UI.
    * This allows the user to right click the list while a context menu is
    * showing and get another context menu.
+   * @param {Event} e
+   * @private
    */
-  private onMenuMousedown_(e: Event): void {
-    if ((e.composedPath()[0] as HTMLElement).tagName !== 'DIALOG') {
+  onMenuMousedown_(e) {
+    if (e.path[0].tagName !== 'DIALOG') {
       return;
     }
 
     this.closeCommandMenu();
   }
 
-  private onOpenCancelTap_() {
-    (this.$.openDialog.get() as CrDialogElement).cancel();
+  /** @private */
+  onOpenCancelTap_() {
+    this.$.openDialog.get().cancel();
   }
 
-  private onOpenConfirmTap_() {
-    const confirmOpenCallback = assert(this.confirmOpenCallback_!);
-    confirmOpenCallback();
-    (this.$.openDialog.get() as CrDialogElement).close();
+  /** @private */
+  onOpenConfirmTap_() {
+    this.confirmOpenCallback_();
+    this.$.openDialog.get().close();
   }
 
-  static getInstance(): BookmarksCommandManagerElement {
-    return assert(instance)!;
+  /** @return {!BookmarksCommandManagerElement} */
+  static getInstance() {
+    return assert(instance);
   }
 }
 
diff --git a/chrome/browser/resources/bookmarks/constants.js b/chrome/browser/resources/bookmarks/constants.js
new file mode 100644
index 0000000..4d27fc7
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/constants.js
@@ -0,0 +1,106 @@
+// Copyright 2017 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.
+
+/**
+ * Enumeration of valid drop locations relative to an element. These are
+ * bit masks to allow combining multiple locations in a single value.
+ * @enum {number}
+ * @const
+ */
+export const DropPosition = {
+  NONE: 0,
+  ABOVE: 1,
+  ON: 2,
+  BELOW: 4,
+};
+
+/**
+ * Commands which can be handled by the CommandManager. This enum is also used
+ * for metrics and should be kept in sync with BookmarkManagerCommand in
+ * enums.xml. Values must never be renumbered or reused.
+ * @enum {number}
+ * @const
+ */
+export const Command = {
+  EDIT: 0,
+  COPY_URL: 1,
+  SHOW_IN_FOLDER: 2,
+  DELETE: 3,
+  OPEN_NEW_TAB: 4,
+  OPEN_NEW_WINDOW: 5,
+  OPEN_INCOGNITO: 6,
+  UNDO: 7,
+  REDO: 8,
+  // OPEN triggers when you double-click an item. NOT USED FOR METRICS.
+  OPEN: 9,
+  SELECT_ALL: 10,
+  DESELECT_ALL: 11,
+  COPY: 12,
+  CUT: 13,
+  PASTE: 14,
+  SORT: 15,
+  ADD_BOOKMARK: 16,
+  ADD_FOLDER: 17,
+  IMPORT: 18,
+  EXPORT: 19,
+  HELP_CENTER: 20,
+
+  // Added for more precise metrics purposes. OPEN is re-mapped to one of these.
+  OPEN_BOOKMARK: 21,
+  OPEN_FOLDER: 22,
+
+  // Append new values to the end of the enum.
+  MAX_VALUE: 23,
+};
+
+/**
+ * Where the menu was opened from. This enum is also used for metrics and should
+ * be kept in sync with BookmarkManagerMenuSource in enums.xml. Values must
+ * never be renumbered or reused.
+ * @enum {number}
+ * @const
+ */
+export const MenuSource = {
+  NONE: 0,
+  ITEM: 1,
+  TREE: 2,
+  TOOLBAR: 3,
+  LIST: 4,
+
+  // Append new values to the end of the enum.
+  NUM_VALUES: 5,
+};
+
+/**
+ * Mirrors the C++ enum from IncognitoModePrefs.
+ * @enum {number}
+ * @const
+ */
+export const IncognitoAvailability = {
+  ENABLED: 0,
+  DISABLED: 1,
+  FORCED: 2,
+};
+
+/** @const */
+export const LOCAL_STORAGE_FOLDER_STATE_KEY = 'folderOpenState';
+
+/** @const */
+export const LOCAL_STORAGE_TREE_WIDTH_KEY = 'treeWidth';
+
+/** @const */
+export const ROOT_NODE_ID = '0';
+
+/** @const */
+export const BOOKMARKS_BAR_ID = '1';
+
+/** @const {number} */
+export const OPEN_CONFIRMATION_LIMIT = 15;
+
+/**
+ * Folders that are beneath this depth will be closed by default in the folder
+ * tree (where the Bookmarks Bar folder is at depth 0).
+ * @const {number}
+ */
+export const FOLDER_OPEN_BY_DEFAULT_DEPTH = 1;
diff --git a/chrome/browser/resources/bookmarks/constants.ts b/chrome/browser/resources/bookmarks/constants.ts
deleted file mode 100644
index a5ff3ffb..0000000
--- a/chrome/browser/resources/bookmarks/constants.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2017 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.
-
-/**
- * Enumeration of valid drop locations relative to an element. These are
- * bit masks to allow combining multiple locations in a single value.
- */
-export enum DropPosition {
-  NONE = 0,
-  ABOVE = 1,
-  ON = 2,
-  BELOW = 4,
-}
-
-/**
- * Commands which can be handled by the CommandManager. This enum is also used
- * for metrics and should be kept in sync with BookmarkManagerCommand in
- * enums.xml. Values must never be renumbered or reused.
- */
-export enum Command {
-  EDIT = 0,
-  COPY_URL = 1,
-  SHOW_IN_FOLDER = 2,
-  DELETE = 3,
-  OPEN_NEW_TAB = 4,
-  OPEN_NEW_WINDOW = 5,
-  OPEN_INCOGNITO = 6,
-  UNDO = 7,
-  REDO = 8,
-  // OPEN triggers when you double-click an item. NOT USED FOR METRICS.
-  OPEN = 9,
-  SELECT_ALL = 10,
-  DESELECT_ALL = 11,
-  COPY = 12,
-  CUT = 13,
-  PASTE = 14,
-  SORT = 15,
-  ADD_BOOKMARK = 16,
-  ADD_FOLDER = 17,
-  IMPORT = 18,
-  EXPORT = 19,
-  HELP_CENTER = 20,
-
-  // Added for more precise metrics purposes. OPEN is re-mapped to one of these.
-  OPEN_BOOKMARK = 21,
-  OPEN_FOLDER = 22,
-
-  // Append new values to the end of the enum.
-  MAX_VALUE = 23,
-}
-
-/**
- * Where the menu was opened from. This enum is also used for metrics and should
- * be kept in sync with BookmarkManagerMenuSource in enums.xml. Values must
- * never be renumbered or reused.
- */
-export enum MenuSource {
-  NONE = 0,
-  ITEM = 1,
-  TREE = 2,
-  TOOLBAR = 3,
-  LIST = 4,
-
-  // Append new values to the end of the enum.
-  NUM_VALUES = 5,
-}
-
-/**
- * Mirrors the C++ enum from IncognitoModePrefs.
- */
-export enum IncognitoAvailability {
-  ENABLED = 0,
-  DISABLED = 1,
-  FORCED = 2,
-}
-
-export const LOCAL_STORAGE_FOLDER_STATE_KEY: string = 'folderOpenState';
-
-export const LOCAL_STORAGE_TREE_WIDTH_KEY: string = 'treeWidth';
-
-export const ROOT_NODE_ID: string = '0';
-
-export const BOOKMARKS_BAR_ID: string = '1';
-
-export const OPEN_CONFIRMATION_LIMIT: number = 15;
-
-/**
- * Folders that are beneath this depth will be closed by default in the folder
- * tree (where the Bookmarks Bar folder is at depth 0).
- */
-export const FOLDER_OPEN_BY_DEFAULT_DEPTH: number = 1;
diff --git a/chrome/browser/resources/bookmarks/debouncer.ts b/chrome/browser/resources/bookmarks/debouncer.js
similarity index 69%
rename from chrome/browser/resources/bookmarks/debouncer.ts
rename to chrome/browser/resources/bookmarks/debouncer.js
index fc33438..feefd5b 100644
--- a/chrome/browser/resources/bookmarks/debouncer.ts
+++ b/chrome/browser/resources/bookmarks/debouncer.js
@@ -12,25 +12,28 @@
  */
 
 export class Debouncer {
-  private callback_: () => void;
-  private timer_: number|null = null;
-  private timerProxy_: Window;
-  private boundTimerCallback_: () => void;
-  private isDone_: boolean = false;
-  private promiseResolver_: PromiseResolver<void>;
-
-  constructor(callback: () => void) {
+  /** @param {!function()} callback */
+  constructor(callback) {
+    /** @private {!function()} */
     this.callback_ = callback;
+    /** @private {!Object} */
     this.timerProxy_ = window;
+    /** @private {?number} */
+    this.timer_ = null;
+    /** @private {!function()} */
     this.boundTimerCallback_ = this.timerCallback_.bind(this);
+    /** @private {boolean} */
+    this.isDone_ = false;
+    /** @private {!PromiseResolver} */
     this.promiseResolver_ = new PromiseResolver();
   }
 
   /**
    * Starts the timer for the callback, cancelling the old timer if there is
    * one.
+   * @param {number=} delay
    */
-  restartTimeout(delay?: number) {
+  restartTimeout(delay) {
     assert(!this.isDone_);
 
     this.cancelTimeout_();
@@ -38,11 +41,17 @@
         this.timerProxy_.setTimeout(this.boundTimerCallback_, delay || 0);
   }
 
-  done(): boolean {
+  /**
+   * @return {boolean} True if the Debouncer has finished processing.
+   */
+  done() {
     return this.isDone_;
   }
 
-  get promise(): Promise<void> {
+  /**
+   * @return {!Promise} Promise which resolves immediately after the callback.
+   */
+  get promise() {
     return this.promiseResolver_.promise;
   }
 
@@ -58,16 +67,18 @@
   /**
    * Cancel the timer callback, which can be restarted by calling
    * restartTimeout().
+   * @private
    */
-  private cancelTimeout_() {
+  cancelTimeout_() {
     if (this.timer_) {
       this.timerProxy_.clearTimeout(this.timer_);
     }
   }
 
-  private timerCallback_() {
+  /** @private */
+  timerCallback_() {
     this.isDone_ = true;
-    this.callback_.call(this);
+    this.callback_.call();
     this.promiseResolver_.resolve();
   }
 }
diff --git a/chrome/browser/resources/bookmarks/dialog_focus_manager.ts b/chrome/browser/resources/bookmarks/dialog_focus_manager.js
similarity index 65%
rename from chrome/browser/resources/bookmarks/dialog_focus_manager.ts
rename to chrome/browser/resources/bookmarks/dialog_focus_manager.js
index 499ef3b3..7fcc53dc 100644
--- a/chrome/browser/resources/bookmarks/dialog_focus_manager.ts
+++ b/chrome/browser/resources/bookmarks/dialog_focus_manager.js
@@ -2,9 +2,6 @@
 // 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_dialog/cr_dialog.m.js';
-
-import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 
 /**
@@ -13,10 +10,19 @@
  * first dialog was opened.
  */
 export class DialogFocusManager {
-  private previousFocusElement_: HTMLElement|null = null;
-  private dialogs_: Set<HTMLDialogElement|CrDialogElement> = new Set();
+  constructor() {
+    /** @private {HTMLElement} */
+    this.previousFocusElement_ = null;
 
-  showDialog(dialog: (HTMLDialogElement|CrDialogElement), showFn?: () => void) {
+    /** @private {Set<HTMLDialogElement>} */
+    this.dialogs_ = new Set();
+  }
+
+  /**
+   * @param {HTMLDialogElement} dialog
+   * @param {function()=} showFn
+   */
+  showDialog(dialog, showFn) {
     if (!showFn) {
       showFn = function() {
         dialog.showModal();
@@ -39,9 +45,9 @@
   }
 
   /**
-   * @return True if the document currently has an open dialog.
+   * @return {boolean} True if the document currently has an open dialog.
    */
-  hasOpenDialog(): boolean {
+  hasOpenDialog() {
     return this.dialogs_.size > 0;
   }
 
@@ -53,22 +59,31 @@
     this.previousFocusElement_ = null;
   }
 
-  private updatePreviousFocus_() {
+  /** @private */
+  updatePreviousFocus_() {
     this.previousFocusElement_ = this.getFocusedElement_();
   }
 
-  private getFocusedElement_(): HTMLElement {
-    let focus = document.activeElement as HTMLElement;
-    while (focus.shadowRoot && focus.shadowRoot!.activeElement) {
-      focus = focus.shadowRoot!.activeElement as HTMLElement;
+  /**
+   * @return {HTMLElement}
+   * @private
+   */
+  getFocusedElement_() {
+    let focus = document.activeElement;
+    while (focus.root && focus.root.activeElement) {
+      focus = focus.root.activeElement;
     }
 
     return focus;
   }
 
-  private getCloseListener_(dialog: (HTMLDialogElement|CrDialogElement)):
-      ((p1: Event) => void) {
-    const closeListener = (e: Event) => {
+  /**
+   * @param {HTMLDialogElement} dialog
+   * @return {function(Event)}
+   * @private
+   */
+  getCloseListener_(dialog) {
+    const closeListener = (e) => {
       // If the dialog is open, then it got reshown immediately and we
       // shouldn't clear it until it is closed again.
       if (dialog.open) {
@@ -87,13 +102,16 @@
     return closeListener;
   }
 
-  static getInstance(): DialogFocusManager {
+  /** @return {!DialogFocusManager} */
+  static getInstance() {
     return instance || (instance = new DialogFocusManager());
   }
 
-  static setInstance(obj: DialogFocusManager|null) {
+  /** @param {?DialogFocusManager} obj */
+  static setInstance(obj) {
     instance = obj;
   }
 }
 
-let instance: DialogFocusManager|null = null;
+/** @type {?DialogFocusManager} */
+let instance = null;
diff --git a/chrome/browser/resources/bookmarks/dnd_manager.ts b/chrome/browser/resources/bookmarks/dnd_manager.js
similarity index 64%
rename from chrome/browser/resources/bookmarks/dnd_manager.ts
rename to chrome/browser/resources/bookmarks/dnd_manager.js
index 5dd64f33..336b933 100644
--- a/chrome/browser/resources/bookmarks/dnd_manager.ts
+++ b/chrome/browser/resources/bookmarks/dnd_manager.js
@@ -2,11 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import './folder_node.js';
-import './item.js';
-
 import {assert} from 'chrome://resources/js/assert.m.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.m.js';
 import {isTextInputElement} from 'chrome://resources/js/util.m.js';
 
 import {changeFolderOpen, deselectItems, selectItem} from './actions.js';
@@ -14,54 +10,75 @@
 import {DropPosition, ROOT_NODE_ID} from './constants.js';
 import {Debouncer} from './debouncer.js';
 import {BookmarksFolderNodeElement} from './folder_node.js';
-import {BookmarksItemElement} from './item.js';
 import {Store} from './store.js';
-import {BookmarkElement, BookmarkNode, DragData, DropDestination, NodeMap, ObjectMap} from './types.js';
+import {BookmarkElement, BookmarkNode, DragData, DropDestination} from './types.js';
 import {canEditNode, canReorderChildren, getDisplayedList, hasChildFolders, isShowingSearch, normalizeNode} from './util.js';
 
-type NormalizedDragData = {
-  elements: BookmarkNode[],
-  sameProfile: boolean,
-};
+/** @typedef {?{elements: !Array<BookmarkNode>, sameProfile: boolean}} */
+let NormalizedDragData;
 
-const DRAG_THRESHOLD: number = 15;
+/** @const {number} */
+const DRAG_THRESHOLD = 15;
 
-function isBookmarkItem(element: Element): boolean {
+/**
+ * @param {Element} element
+ * @return {boolean}
+ */
+function isBookmarkItem(element) {
   return element.tagName === 'BOOKMARKS-ITEM';
 }
 
-function isBookmarkFolderNode(element: Element): boolean {
+/**
+ * @param {Element} element
+ * @return {boolean}
+ */
+function isBookmarkFolderNode(element) {
   return element.tagName === 'BOOKMARKS-FOLDER-NODE';
 }
 
-function isBookmarkList(element: Element): boolean {
+/**
+ * @param {Element} element
+ * @return {boolean}
+ */
+function isBookmarkList(element) {
   return element.tagName === 'BOOKMARKS-LIST';
 }
 
-function isClosedBookmarkFolderNode(element: Element): boolean {
-  return isBookmarkFolderNode(element) &&
-      !((element as BookmarksFolderNodeElement).isOpen);
+/**
+ * @param {Element} element
+ * @return {boolean}
+ */
+function isClosedBookmarkFolderNode(element) {
+  return isBookmarkFolderNode(/** @type {BookmarkElement} */ (element)) &&
+      !(/** @type {BookmarksFolderNodeElement} */ (element).isOpen);
 }
 
-function getBookmarkElement(path?: EventTarget[]): BookmarkElement|null {
+/**
+ * @param {Array<!Element>|undefined} path
+ * @return {BookmarkElement}
+ */
+function getBookmarkElement(path) {
   if (!path) {
     return null;
   }
 
-  for (let i = 0; i < path!.length; i++) {
-    const element = path![i] as Element;
-    if (isBookmarkItem(element) || isBookmarkFolderNode(element) ||
-        isBookmarkList(element)) {
-      return path![i] as BookmarkElement;
+  for (let i = 0; i < path.length; i++) {
+    if (isBookmarkItem(path[i]) || isBookmarkFolderNode(path[i]) ||
+        isBookmarkList(path[i])) {
+      return /** @type {BookmarkElement} */ (path[i]);
     }
   }
   return null;
 }
 
-function getDragElement(path: EventTarget[]): BookmarkElement|null {
+/**
+ * @param {Array<!Element>|undefined} path
+ * @return {BookmarkElement}
+ */
+function getDragElement(path) {
   const dragElement = getBookmarkElement(path);
   for (let i = 0; i < path.length; i++) {
-    if ((path![i] as Element).tagName === 'BUTTON') {
+    if (path[i].tagName === 'BUTTON') {
       return null;
     }
   }
@@ -69,8 +86,12 @@
                                                                 null;
 }
 
-function getBookmarkNode(bookmarkElement: BookmarkElement): BookmarkNode {
-  return Store.getInstance().data.nodes[bookmarkElement.itemId]!;
+/**
+ * @param {BookmarkElement} bookmarkElement
+ * @return {BookmarkNode}
+ */
+function getBookmarkNode(bookmarkElement) {
+  return Store.getInstance().data.nodes[bookmarkElement.itemId];
 }
 
 /**
@@ -78,12 +99,16 @@
  * bookmarkManagerPrivate API.
  */
 export class DragInfo {
-  dragData: NormalizedDragData|null = null;
+  constructor() {
+    /** @type {NormalizedDragData} */
+    this.dragData = null;
+  }
 
-  setNativeDragData(newDragData: DragData) {
+  /** @param {DragData} newDragData */
+  setNativeDragData(newDragData) {
     this.dragData = {
       sameProfile: newDragData.sameProfile,
-      elements: newDragData.elements!.map((x) => normalizeNode(x))
+      elements: newDragData.elements.map((x) => normalizeNode(x))
     };
   }
 
@@ -91,44 +116,50 @@
     this.dragData = null;
   }
 
-  isDragValid(): boolean {
+  /** @return {boolean} */
+  isDragValid() {
     return !!this.dragData;
   }
 
-  isSameProfile(): boolean {
+  /** @return {boolean} */
+  isSameProfile() {
     return !!this.dragData && this.dragData.sameProfile;
   }
 
-  isDraggingFolders(): boolean {
+  /** @return {boolean} */
+  isDraggingFolders() {
     return !!this.dragData && this.dragData.elements.some(function(node) {
       return !node.url;
     });
   }
 
-  isDraggingBookmark(bookmarkId: string): boolean {
+  /** @return {boolean} */
+  isDraggingBookmark(bookmarkId) {
     return !!this.dragData && this.isSameProfile() &&
         this.dragData.elements.some(function(node) {
           return node.id === bookmarkId;
         });
   }
 
-  isDraggingChildBookmark(folderId: string): boolean {
+  /** @return {boolean} */
+  isDraggingChildBookmark(folderId) {
     return !!this.dragData && this.isSameProfile() &&
         this.dragData.elements.some(function(node) {
           return node.parentId === folderId;
         });
   }
 
-  isDraggingFolderToDescendant(itemId: string, nodes: NodeMap): boolean {
+  /** @return {boolean} */
+  isDraggingFolderToDescendant(itemId, nodes) {
     if (!this.isSameProfile()) {
       return false;
     }
 
-    let parentId = nodes[itemId]!.parentId;
-    const parents: ObjectMap<boolean> = {};
+    let parentId = nodes[itemId].parentId;
+    const parents = {};
     while (parentId) {
       parents[parentId] = true;
-      parentId = nodes[parentId]!.parentId;
+      parentId = nodes[parentId].parentId;
     }
 
     return !!this.dragData && this.dragData.elements.some(function(node) {
@@ -141,19 +172,26 @@
  * Manages auto expanding of sidebar folders on hover while dragging.
  */
 class AutoExpander {
-  EXPAND_FOLDER_DELAY: number = 400;
-  private lastElement_: BookmarkElement|null = null;
-  private debouncer_: Debouncer;
-
   constructor() {
+    /** @const {number} */
+    this.EXPAND_FOLDER_DELAY = 400;
+
+    /** @private {?BookmarkElement} */
+    this.lastElement_ = null;
+
+    /** @type {!Debouncer} */
     this.debouncer_ = new Debouncer(() => {
       const store = Store.getInstance();
-      store.dispatch(changeFolderOpen(this.lastElement_!.itemId, true));
+      store.dispatch(changeFolderOpen(this.lastElement_.itemId, true));
       this.reset();
     });
   }
 
-  update(e: Event, overElement: BookmarkElement|null) {
+  /**
+   * @param {Event} e
+   * @param {?BookmarkElement} overElement
+   */
+  update(e, overElement) {
     const itemId = overElement ? overElement.itemId : null;
     const store = Store.getInstance();
 
@@ -161,7 +199,7 @@
     // expander. Falls through to reset the expander delay.
     if (overElement && overElement !== this.lastElement_ &&
         isClosedBookmarkFolderNode(overElement) &&
-        hasChildFolders(itemId as string, store.data.nodes)) {
+        hasChildFolders(/** @type {string} */ (itemId), store.data.nodes)) {
       this.reset();
       this.lastElement_ = overElement;
     }
@@ -187,28 +225,45 @@
  * between items or highlights folders which are valid drop targets.
  */
 class DropIndicator {
-  private removeDropIndicatorTimeoutId_: number|null;
-  private lastIndicatorElement_: BookmarkElement|null;
-  private lastIndicatorClassName_: string|null;
-  timerProxy: Window;
-
   constructor() {
+    /**
+     * @private {number|null} Timer id used to help minimize flicker.
+     */
     this.removeDropIndicatorTimeoutId_ = null;
+
+    /**
+     * The element that had a style applied it to indicate the drop location.
+     * This is used to easily remove the style when necessary.
+     * @private {BookmarkElement|null}
+     */
     this.lastIndicatorElement_ = null;
+
+    /**
+     * The style that was applied to indicate the drop location.
+     * @private {?string|null}
+     */
     this.lastIndicatorClassName_ = null;
+
+    /**
+     * Used to instantly remove the indicator style in tests.
+     * @private {!Object}
+     */
     this.timerProxy = window;
   }
 
   /**
    * Applies the drop indicator style on the target element and stores that
    * information to easily remove the style in the future.
+   * @param {HTMLElement} indicatorElement
+   * @param {DropPosition} position
    */
-  addDropIndicatorStyle(indicatorElement: HTMLElement, position: DropPosition) {
+  addDropIndicatorStyle(indicatorElement, position) {
     const indicatorStyleName = position === DropPosition.ABOVE ?
         'drag-above' :
         position === DropPosition.BELOW ? 'drag-below' : 'drag-on';
 
-    this.lastIndicatorElement_ = indicatorElement as BookmarkElement;
+    this.lastIndicatorElement_ =
+        /** @type {BookmarkElement} */ (indicatorElement);
     this.lastIndicatorClassName_ = indicatorStyleName;
 
     indicatorElement.classList.add(indicatorStyleName);
@@ -230,12 +285,13 @@
   /**
    * Displays the drop indicator on the current drop target to give the
    * user feedback on where the drop will occur.
+   * @param {DropDestination} dropDest
    */
-  update(dropDest: DropDestination) {
-    this.timerProxy.clearTimeout(this.removeDropIndicatorTimeoutId_!);
+  update(dropDest) {
+    this.timerProxy.clearTimeout(this.removeDropIndicatorTimeoutId_);
     this.removeDropIndicatorTimeoutId_ = null;
 
-    const indicatorElement = dropDest.element.getDropTarget()!;
+    const indicatorElement = dropDest.element.getDropTarget();
     const position = dropDest.position;
 
     this.removeDropIndicatorStyle();
@@ -262,20 +318,29 @@
  * Manages drag and drop events for the bookmarks-app.
  */
 export class DNDManager {
-  private dragInfo_: DragInfo|null;
-  private dropDestination_: DropDestination|null;
-  private dropIndicator_: DropIndicator|null;
-  private eventTracker_: EventTracker = new EventTracker();
-  private autoExpander_: AutoExpander|null;
-  private timerProxy_: any;
-  private lastPointerWasTouch_: boolean;
-
   constructor() {
+    /** @private {DragInfo} */
     this.dragInfo_ = null;
+
+    /** @private {?DropDestination} */
     this.dropDestination_ = null;
+
+    /** @private {DropIndicator} */
     this.dropIndicator_ = null;
+
+    /** @private {Object<string, function(!Event)>} */
+    this.documentListeners_ = null;
+
+    /** @private {?AutoExpander} */
     this.autoExpander_ = null;
+
+    /**
+     * Used to instantly clearDragData in tests.
+     * @private {!Object}
+     */
     this.timerProxy_ = window;
+
+    /** @private {boolean} */
     this.lastPointerWasTouch_ = false;
   }
 
@@ -284,14 +349,19 @@
     this.dropIndicator_ = new DropIndicator();
     this.autoExpander_ = new AutoExpander();
 
-    this.eventTracker_.add(document, 'dragstart', e => this.onDragStart_(e));
-    this.eventTracker_.add(document, 'dragenter', e => this.onDragEnter_(e));
-    this.eventTracker_.add(document, 'dragover', e => this.onDragOver_(e));
-    this.eventTracker_.add(document, 'dragleave', () => this.onDragLeave_());
-    this.eventTracker_.add(document, 'drop', e => this.onDrop_(e));
-    this.eventTracker_.add(document, 'dragend', () => this.clearDragData_());
-    this.eventTracker_.add(document, 'mousedown', () => this.onMouseDown_());
-    this.eventTracker_.add(document, 'touchstart', () => this.onTouchStart_());
+    this.documentListeners_ = {
+      'dragstart': this.onDragStart_.bind(this),
+      'dragenter': this.onDragEnter_.bind(this),
+      'dragover': this.onDragOver_.bind(this),
+      'dragleave': this.onDragLeave_.bind(this),
+      'drop': this.onDrop_.bind(this),
+      'dragend': this.clearDragData_.bind(this),
+      'mousedown': this.onMouseDown_.bind(this),
+      'touchstart': this.onTouchStart_.bind(this),
+    };
+    for (const event in this.documentListeners_) {
+      document.addEventListener(event, this.documentListeners_[event]);
+    }
 
     chrome.bookmarkManagerPrivate.onDragEnter.addListener(
         this.handleChromeDragEnter_.bind(this));
@@ -300,14 +370,20 @@
   }
 
   destroy() {
-    this.eventTracker_.removeAll();
+    for (const event in this.documentListeners_) {
+      document.removeEventListener(event, this.documentListeners_[event]);
+    }
   }
 
   ////////////////////////////////////////////////////////////////////////////
   // DragEvent handlers:
 
-  private onDragStart_(e: Event) {
-    const dragElement = getDragElement(e.composedPath());
+  /**
+   * @private
+   * @param {Event} e
+   */
+  onDragStart_(e) {
+    const dragElement = getDragElement(e.path);
     if (!dragElement) {
       return;
     }
@@ -330,14 +406,14 @@
       // delay on large amount of bookmark dragging.
       for (const itemId of displayingItems) {
         for (const element of dragData.elements) {
-          if (element!.id === itemId) {
-            draggedNodes.push(element!.id);
+          if (element.id === itemId) {
+            draggedNodes.push(element.id);
             break;
           }
         }
       }
     } else {
-      draggedNodes = dragData.elements.map((item) => item!.id);
+      draggedNodes = dragData.elements.map((item) => item.id);
     }
 
     assert(draggedNodes.length === dragData.elements.length);
@@ -346,17 +422,22 @@
     assert(dragNodeIndex !== -1);
 
     chrome.bookmarkManagerPrivate.startDrag(
-        draggedNodes, dragNodeIndex, this.lastPointerWasTouch_,
-        (e as DragEvent).clientX, (e as DragEvent).clientY);
+        draggedNodes, dragNodeIndex, this.lastPointerWasTouch_, e.clientX,
+        e.clientY);
   }
 
-  private onDragLeave_() {
-    this.dropIndicator_!.finish();
+  /** @private */
+  onDragLeave_() {
+    this.dropIndicator_.finish();
   }
 
-  private onDrop_(e: Event) {
+  /**
+   * @private
+   * @param {!Event} e
+   */
+  onDrop_(e) {
     // Allow normal DND on text inputs.
-    if (isTextInputElement((e.composedPath()[0] as HTMLElement))) {
+    if (isTextInputElement(e.path[0])) {
       return;
     }
 
@@ -378,15 +459,23 @@
     this.clearDragData_();
   }
 
-  private onDragEnter_(e: Event) {
+  /**
+   * @private
+   * @param {Event} e
+   */
+  onDragEnter_(e) {
     e.preventDefault();
   }
 
-  private onDragOver_(e: Event) {
+  /**
+   * @private
+   * @param {Event} e
+   */
+  onDragOver_(e) {
     this.dropDestination_ = null;
 
     // Allow normal DND on text inputs.
-    if (isTextInputElement(e.composedPath()[0] as HTMLElement)) {
+    if (isTextInputElement(e.path[0])) {
       return;
     }
 
@@ -394,62 +483,72 @@
     // navigation. We never want to do that for the bookmark manager.
     e.preventDefault();
 
-    if (!this.dragInfo_!.isDragValid()) {
+    if (!this.dragInfo_.isDragValid()) {
       return;
     }
 
     const state = Store.getInstance().data;
-    const items = this.dragInfo_!.dragData!.elements;
+    const items = this.dragInfo_.dragData.elements;
 
-    const overElement = getBookmarkElement(e.composedPath());
-    this.autoExpander_!.update(e, overElement);
+    const overElement = getBookmarkElement(e.path);
+    this.autoExpander_.update(e, overElement);
     if (!overElement) {
-      this.dropIndicator_!.finish();
+      this.dropIndicator_.finish();
       return;
     }
 
     // Now we know that we can drop. Determine if we will drop above, on or
     // below based on mouse position etc.
     this.dropDestination_ =
-        this.calculateDropDestination_((e as DragEvent).clientY, overElement);
+        this.calculateDropDestination_(e.clientY, overElement);
     if (!this.dropDestination_) {
-      this.dropIndicator_!.finish();
+      this.dropIndicator_.finish();
       return;
     }
 
-    this.dropIndicator_!.update(this.dropDestination_);
+    this.dropIndicator_.update(this.dropDestination_);
   }
 
-  private onMouseDown_() {
+  /** @private */
+  onMouseDown_() {
     this.lastPointerWasTouch_ = false;
   }
 
-  private onTouchStart_() {
+  /** @private */
+  onTouchStart_() {
     this.lastPointerWasTouch_ = true;
   }
 
-  private handleChromeDragEnter_(dragData: DragData) {
-    this.dragInfo_!.setNativeDragData(dragData);
+  /**
+   * @private
+   * @param {DragData} dragData
+   */
+  handleChromeDragEnter_(dragData) {
+    this.dragInfo_.setNativeDragData(dragData);
   }
 
   ////////////////////////////////////////////////////////////////////////////
   // Helper methods:
 
-  private clearDragData_() {
-    this.autoExpander_!.reset();
+  /** @private */
+  clearDragData_() {
+    this.autoExpander_.reset();
 
     // Defer the clearing of the data so that the bookmark manager API's drop
     // event doesn't clear the drop data before the web drop event has a
     // chance to execute (on Mac).
     this.timerProxy_.setTimeout(() => {
-      this.dragInfo_!.clearDragData();
+      this.dragInfo_.clearDragData();
       this.dropDestination_ = null;
-      this.dropIndicator_!.finish();
+      this.dropIndicator_.finish();
     }, 0);
   }
 
-  private calculateDropInfo_(dropDestination: DropDestination):
-      {parentId: string, index: number} {
+  /**
+   * @param {DropDestination} dropDestination
+   * @return {{parentId: string, index: number}}
+   */
+  calculateDropInfo_(dropDestination) {
     if (isBookmarkList(dropDestination.element)) {
       return {
         index: 0,
@@ -467,8 +566,8 @@
 
       // Drops between items in the normal list and the sidebar use the drop
       // destination node's parent.
-      parentId = assert(node.parentId!);
-      index = state.nodes[parentId]!.children!.indexOf(node.id);
+      parentId = assert(node.parentId);
+      index = state.nodes[parentId].children.indexOf(node.id);
 
       if (position === DropPosition.BELOW) {
         index++;
@@ -484,8 +583,10 @@
   /**
    * Calculates which items should be dragged based on the initial drag item
    * and the current selection. Dragged items will end up selected.
+   * @param {!BookmarkElement} dragElement
+   * @private
    */
-  private calculateDragData_(dragElement: BookmarkElement) {
+  calculateDragData_(dragElement) {
     const dragId = dragElement.itemId;
     const store = Store.getInstance();
     const state = store.data;
@@ -524,10 +625,15 @@
 
   /**
    * This function determines where the drop will occur.
+   * @private
+   * @param {number} elementClientY
+   * @param {!BookmarkElement} overElement
+   * @return {?DropDestination} If no valid drop position is found, null,
+   *   otherwise:
+   *       element - The target element that will receive the drop.
+   *       position - A |DropPosition| relative to the |element|.
    */
-  private calculateDropDestination_(
-      elementClientY: number,
-      overElement: BookmarkElement): DropDestination|null {
+  calculateDropDestination_(elementClientY, overElement) {
     const validDropPositions = this.calculateValidDropPositions_(overElement);
     if (validDropPositions === DropPosition.NONE) {
       return null;
@@ -536,7 +642,7 @@
     const above = validDropPositions & DropPosition.ABOVE;
     const below = validDropPositions & DropPosition.BELOW;
     const on = validDropPositions & DropPosition.ON;
-    const rect = overElement.getDropTarget()!.getBoundingClientRect();
+    const rect = overElement.getDropTarget().getBoundingClientRect();
     const yRatio = (elementClientY - rect.top) / rect.height;
 
     if (above && (yRatio <= .25 || yRatio <= .5 && (!below || !on))) {
@@ -556,9 +662,13 @@
 
   /**
    * Determines the valid drop positions for the given target element.
+   * @private
+   * @param {!BookmarkElement} overElement The element that we are currently
+   *     dragging over.
+   * @return {number} An bit field enumeration of valid drop locations.
    */
-  private calculateValidDropPositions_(overElement: BookmarkElement): number {
-    const dragInfo = this.dragInfo_!;
+  calculateValidDropPositions_(overElement) {
+    const dragInfo = this.dragInfo_;
     const state = Store.getInstance().data;
     let itemId = overElement.itemId;
 
@@ -591,8 +701,13 @@
     return validDropPositions;
   }
 
-  private calculateDropAboveBelow_(overElement: BookmarkElement): number {
-    const dragInfo = this.dragInfo_!;
+  /**
+   * @private
+   * @param {BookmarkElement} overElement
+   * @return {number}
+   */
+  calculateDropAboveBelow_(overElement) {
+    const dragInfo = this.dragInfo_;
     const state = Store.getInstance().data;
 
     if (isBookmarkList(overElement)) {
@@ -614,8 +729,7 @@
     let validDropPositions = DropPosition.NONE;
 
     // Cannot drop above if the item above is already in the drag source.
-    const previousElem =
-        overElement.previousElementSibling as BookmarksFolderNodeElement;
+    const previousElem = overElement.previousElementSibling;
     if (!previousElem || !dragInfo.isDraggingBookmark(previousElem.itemId)) {
       validDropPositions |= DropPosition.ABOVE;
     }
@@ -627,8 +741,7 @@
       return validDropPositions;
     }
 
-    const nextElement =
-        overElement.nextElementSibling as BookmarksFolderNodeElement;
+    const nextElement = overElement.nextElementSibling;
     // Cannot drop below if the item below is already in the drag source.
     if (!nextElement || !dragInfo.isDraggingBookmark(nextElement.itemId)) {
       validDropPositions |= DropPosition.BELOW;
@@ -639,13 +752,18 @@
 
   /**
    * Determine whether we can drop the dragged items on the drop target.
+   * @private
+   * @param {!BookmarkElement} overElement The element that we are currently
+   *     dragging over.
+   * @return {boolean} Whether we can drop the dragged items on the drop
+   *     target.
    */
-  private canDropOn_(overElement: BookmarkElement): boolean {
+  canDropOn_(overElement) {
     // Allow dragging onto empty bookmark lists.
     if (isBookmarkList(overElement)) {
       const state = Store.getInstance().data;
       return !!state.selectedFolder &&
-          state.nodes[state.selectedFolder]!.children!.length === 0;
+          state.nodes[state.selectedFolder].children.length === 0;
     }
 
     // We can only drop on a folder.
@@ -653,16 +771,21 @@
       return false;
     }
 
-    return !this.dragInfo_!.isDraggingChildBookmark(overElement.itemId);
+    return !this.dragInfo_.isDraggingChildBookmark(overElement.itemId);
   }
 
-  private shouldHighlight_(dropDestination: DropDestination): boolean {
+  /**
+   * @param {DropDestination} dropDestination
+   * @private
+   */
+  shouldHighlight_(dropDestination) {
     return isBookmarkItem(dropDestination.element) ||
         isBookmarkList(dropDestination.element);
   }
 
-  setTimerProxyForTesting(timerProxy: any) {
+  /** @param {!Object} timerProxy */
+  setTimerProxyForTesting(timerProxy) {
     this.timerProxy_ = timerProxy;
-    this.dropIndicator_!.timerProxy = timerProxy;
+    this.dropIndicator_.timerProxy = timerProxy;
   }
 }
diff --git a/chrome/browser/resources/bookmarks/edit_dialog.ts b/chrome/browser/resources/bookmarks/edit_dialog.js
similarity index 72%
rename from chrome/browser/resources/bookmarks/edit_dialog.ts
rename to chrome/browser/resources/bookmarks/edit_dialog.js
index 87546f0..70c3c2b8 100644
--- a/chrome/browser/resources/bookmarks/edit_dialog.ts
+++ b/chrome/browser/resources/bookmarks/edit_dialog.js
@@ -8,8 +8,6 @@
 import 'chrome://resources/cr_elements/shared_style_css.m.js';
 import './strings.m.js';
 
-import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
-import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -18,13 +16,7 @@
 import {DialogFocusManager} from './dialog_focus_manager.js';
 import {BookmarkNode} from './types.js';
 
-export interface BookmarksEditDialogElement {
-  $: {
-    dialog: CrDialogElement,
-    url: CrInputElement,
-  }
-}
-
+/** @polymer */
 export class BookmarksEditDialogElement extends PolymerElement {
   static get is() {
     return 'bookmarks-edit-dialog';
@@ -36,45 +28,53 @@
 
   static get properties() {
     return {
+      /** @private */
       isFolder_: Boolean,
+
+      /** @private */
       isEdit_: Boolean,
 
       /**
        * Item that is being edited, or null when adding.
+       * @private {?BookmarkNode}
        */
       editItem_: Object,
 
       /**
        * Parent node for the item being added, or null when editing.
+       * @private {?string}
        */
       parentId_: String,
+
+      /** @private */
       titleValue_: String,
+
+      /** @private */
       urlValue_: String,
     };
   }
 
-  private isFolder_: boolean;
-  private isEdit_: boolean;
-  private editItem_: BookmarkNode|null;
-  private parentId_: string|null;
-  private titleValue_: string;
-  private urlValue_: string;
-
   /**
    * Show the dialog to add a new folder (if |isFolder|) or item, which will be
    * inserted into the tree as a child of |parentId|.
+   * @param {boolean} isFolder
+   * @param {string} parentId
    */
-  showAddDialog(isFolder: boolean, parentId: string) {
+  showAddDialog(isFolder, parentId) {
     this.reset_();
     this.isEdit_ = false;
     this.isFolder_ = isFolder;
     this.parentId_ = parentId;
 
-    DialogFocusManager.getInstance().showDialog(this.$.dialog);
+    DialogFocusManager.getInstance().showDialog(
+        /** @type {!HTMLDialogElement} */ (this.$.dialog));
   }
 
-  /** Show the edit dialog for |editItem|. */
-  showEditDialog(editItem: BookmarkNode) {
+  /**
+   * Show the edit dialog for |editItem|.
+   * @param {BookmarkNode} editItem
+   */
+  showEditDialog(editItem) {
     this.reset_();
     this.isEdit_ = true;
     this.isFolder_ = !editItem.url;
@@ -82,16 +82,18 @@
 
     this.titleValue_ = editItem.title;
     if (!this.isFolder_) {
-      this.urlValue_ = assert(editItem.url!);
+      this.urlValue_ = assert(editItem.url);
     }
 
-    DialogFocusManager.getInstance().showDialog(this.$.dialog);
+    DialogFocusManager.getInstance().showDialog(
+        /** @type {!HTMLDialogElement} */ (this.$.dialog));
   }
 
   /**
    * Clear out existing values from the dialog, allowing it to be reused.
+   * @private
    */
-  private reset_() {
+  reset_() {
     this.editItem_ = null;
     this.parentId_ = null;
     this.$.url.invalid = false;
@@ -99,7 +101,13 @@
     this.urlValue_ = '';
   }
 
-  private getDialogTitle_(isFolder: boolean, isEdit: boolean): string {
+  /**
+   * @param {boolean} isFolder
+   * @param {boolean} isEdit
+   * @return {string}
+   * @private
+   */
+  getDialogTitle_(isFolder, isEdit) {
     let title;
     if (isEdit) {
       title = isFolder ? 'renameFolderTitle' : 'editBookmarkTitle';
@@ -113,9 +121,11 @@
   /**
    * Validates the value of the URL field, returning true if it is a valid URL.
    * May modify the value by prepending 'http://' in order to make it valid.
+   * @return {boolean}
+   * @private
    */
-  private validateUrl_(): boolean {
-    const urlInput = this.$.url;
+  validateUrl_() {
+    const urlInput = /** @type {CrInputElement} */ (this.$.url);
     const originalValue = this.urlValue_;
 
     if (urlInput.validate()) {
@@ -132,9 +142,9 @@
     return false;
   }
 
-  private onSaveButtonTap_() {
-    const edit: { title: string, url?: string, parentId?: string|null } =
-        { 'title': this.titleValue_ };
+  /** @private */
+  onSaveButtonTap_() {
+    const edit = {'title': this.titleValue_};
     if (!this.isFolder_) {
       if (!this.validateUrl_()) {
         return;
@@ -144,7 +154,7 @@
     }
 
     if (this.isEdit_) {
-      chrome.bookmarks.update(this.editItem_!.id, edit);
+      chrome.bookmarks.update(this.editItem_.id, edit);
     } else {
       edit['parentId'] = this.parentId_;
       trackUpdatedItems();
@@ -153,7 +163,8 @@
     this.$.dialog.close();
   }
 
-  private onCancelButtonTap_() {
+  /** @private */
+  onCancelButtonTap_() {
     this.$.dialog.cancel();
   }
 }
diff --git a/chrome/browser/resources/bookmarks/folder_node.ts b/chrome/browser/resources/bookmarks/folder_node.js
similarity index 66%
rename from chrome/browser/resources/bookmarks/folder_node.ts
rename to chrome/browser/resources/bookmarks/folder_node.js
index 27a7a1d..d8dbec9a 100644
--- a/chrome/browser/resources/bookmarks/folder_node.ts
+++ b/chrome/browser/resources/bookmarks/folder_node.js
@@ -10,6 +10,7 @@
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
 import {isRTL} from 'chrome://resources/js/util.m.js';
 import {html, microTask, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -20,19 +21,17 @@
 import {BookmarkNode, BookmarksPageState} from './types.js';
 import {hasChildFolders, isShowingSearch} from './util.js';
 
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ */
 const BookmarksFolderNodeElementBase =
-    mixinBehaviors(StoreClient, PolymerElement) as {
-  new (): PolymerElement & BookmarksStoreClientInterface &
-      StoreObserver<BookmarksPageState>;
-}
+    mixinBehaviors(StoreClient, PolymerElement);
 
-export interface BookmarksFolderNodeElement {
-  $: {
-    container: HTMLDivElement,
-    descendants: HTMLDivElement,
-  }
-}
-
+/** @polymer */
 export class BookmarksFolderNodeElement extends BookmarksFolderNodeElementBase {
   static get is() {
     return 'bookmarks-folder-node';
@@ -59,20 +58,27 @@
         computed: 'computeIsOpen_(openState_, depth)',
       },
 
+      /** @type {BookmarkNode} */
       item_: Object,
 
+      /** @private {?boolean} */
       openState_: Boolean,
 
+      /** @private */
       selectedFolder_: String,
 
+      /** @private */
       searchActive_: Boolean,
 
+      /** @private */
       isSelectedFolder_: {
         type: Boolean,
+        value: false,
         reflectToAttribute: true,
         computed: 'computeIsSelected_(itemId, selectedFolder_, searchActive_)'
       },
 
+      /** @private */
       hasChildFolder_: {
         type: Boolean,
         computed: 'computeHasChildFolder_(item_.children)',
@@ -80,16 +86,6 @@
     };
   }
 
-  depth: number;
-  isOpen: boolean;
-  itemId: string;
-  private item_: BookmarkNode;
-  private openState_: boolean;
-  private selectedFolder_: string;
-  private searchActive_: boolean;
-  private isSelectedFolder_: boolean = false;
-  private hasChildFolder_: boolean;
-
   static get observers() {
     return [
       'updateAriaExpanded_(hasChildFolder_, isOpen)',
@@ -107,37 +103,48 @@
   connectedCallback() {
     super.connectedCallback();
     this.watch('item_', state => {
-      return (state as BookmarksPageState).nodes[this.itemId];
+      return /** @type {!BookmarksPageState} */ (state).nodes[this.itemId];
     });
     this.watch('openState_', state => {
-      const bookmarksState = state as BookmarksPageState;
+      const bookmarksState = /** @type {!BookmarksPageState} */ (state);
       return bookmarksState.folderOpenState.has(this.itemId) ?
           bookmarksState.folderOpenState.get(this.itemId) :
           null;
     });
     this.watch('selectedFolder_', state => {
-      return (state as BookmarksPageState).selectedFolder;
+      return /** @type {!BookmarksPageState} */ (state).selectedFolder;
     });
     this.watch('searchActive_', state => {
-      return isShowingSearch(state as BookmarksPageState);
+      return isShowingSearch(/** @type {!BookmarksPageState} */ (state));
     });
 
     this.updateFromStore();
   }
 
-  private getContainerClass_(isSelectedFolder: boolean): string {
+  /**
+   * @param {boolean} isSelectedFolder
+   * @return {string}
+   * @private
+   */
+  getContainerClass_(isSelectedFolder) {
     return isSelectedFolder ? 'selected' : '';
   }
 
-  getFocusTarget(): HTMLElement {
-    return this.$.container;
+  /** @return {!HTMLElement} */
+  getFocusTarget() {
+    return /** @type {!HTMLDivElement} */ (this.$.container);
   }
 
-  getDropTarget(): HTMLElement {
-    return this.$.container;
+  /** @return {HTMLElement} */
+  getDropTarget() {
+    return /** @type {!HTMLDivElement} */ (this.$.container);
   }
 
-  private onKeydown_(e: KeyboardEvent) {
+  /**
+   * @private
+   * @param {!Event} e
+   */
+  onKeydown_(e) {
     let yDirection = 0;
     let xDirection = 0;
     let handled = true;
@@ -160,7 +167,7 @@
     }
 
     this.changeKeyboardSelection_(
-        xDirection, yDirection, this.shadowRoot!.activeElement);
+        xDirection, yDirection, this.root.activeElement);
 
     if (!handled) {
       handled = BookmarksCommandManagerElement.getInstance().handleKeyEvent(
@@ -175,11 +182,16 @@
     e.stopPropagation();
   }
 
-  private changeKeyboardSelection_(
-      xDirection: number, yDirection: number, currentFocus: Element|null) {
+  /**
+   * @private
+   * @param {number} xDirection
+   * @param {number} yDirection
+   * @param {!HTMLElement} currentFocus
+   */
+  changeKeyboardSelection_(xDirection, yDirection, currentFocus) {
     let newFocusFolderNode = null;
-    const isChildFolderNodeFocused = currentFocus &&
-        (currentFocus as HTMLElement)!.tagName === 'BOOKMARKS-FOLDER-NODE';
+    const isChildFolderNodeFocused =
+        currentFocus && currentFocus.tagName === 'BOOKMARKS-FOLDER-NODE';
 
     if (xDirection === 1) {
       // The right arrow opens a folder if closed and goes to the first child
@@ -198,8 +210,8 @@
         this.dispatch(changeFolderOpen(this.item_.id, false));
       } else {
         const parentFolderNode = this.getParentFolderNode_();
-        if (parentFolderNode!.itemId !== ROOT_NODE_ID) {
-          parentFolderNode!.getFocusTarget().focus();
+        if (parentFolderNode.itemId !== ROOT_NODE_ID) {
+          parentFolderNode.getFocusTarget().focus();
         }
       }
     }
@@ -220,7 +232,8 @@
       // Get the next child folder node if a child is focused.
       if (!newFocusFolderNode) {
         newFocusFolderNode = this.getNextChild_(
-            yDirection === -1, (currentFocus! as BookmarksFolderNodeElement));
+            yDirection === -1,
+            /** @type {!BookmarksFolderNodeElement} */ (currentFocus));
       }
 
       // The first child's predecessor is this node.
@@ -232,7 +245,7 @@
     // If there is no newly focused node, allow the parent to handle the change.
     if (!newFocusFolderNode) {
       if (this.itemId !== ROOT_NODE_ID) {
-        this.getParentFolderNode_()!.changeKeyboardSelection_(
+        this.getParentFolderNode_().changeKeyboardSelection_(
             0, yDirection, this);
       }
 
@@ -247,9 +260,13 @@
 
   /**
    * Returns the next or previous visible bookmark node relative to |child|.
+   * @private
+   * @param {boolean} reverse
+   * @param {!BookmarksFolderNodeElement} child
+   * @return {BookmarksFolderNodeElement|null} Returns null if there is no child
+   *     before/after |child|.
    */
-  private getNextChild_(reverse: boolean, child: BookmarksFolderNodeElement):
-      BookmarksFolderNodeElement|null {
+  getNextChild_(reverse, child) {
     let newFocus = null;
     const children = this.getChildFolderNodes_();
 
@@ -259,10 +276,10 @@
       // A child node's predecessor is either the previous child's last visible
       // descendant, or this node, which is its immediate parent.
       newFocus =
-          index === 0 ? null : children[index - 1]!.getLastVisibleDescendant_();
+          index === 0 ? null : children[index - 1].getLastVisibleDescendant_();
     } else if (index < children.length - 1) {
       // A successor to a child is the next child.
-      newFocus = children[index + 1]!;
+      newFocus = children[index + 1];
     }
 
     return newFocus;
@@ -270,86 +287,131 @@
 
   /**
    * Returns the immediate parent folder node, or null if there is none.
+   * @private
+   * @return {BookmarksFolderNodeElement|null}
    */
-  private getParentFolderNode_(): BookmarksFolderNodeElement|null {
+  getParentFolderNode_() {
     let parentFolderNode = this.parentNode;
     while (parentFolderNode &&
-           (parentFolderNode as HTMLElement).tagName !==
-               'BOOKMARKS-FOLDER-NODE') {
-      parentFolderNode =
-          parentFolderNode.parentNode || (parentFolderNode as ShadowRoot).host;
+           parentFolderNode.tagName !== 'BOOKMARKS-FOLDER-NODE') {
+      parentFolderNode = parentFolderNode.parentNode || parentFolderNode.host;
     }
-    return (parentFolderNode as BookmarksFolderNodeElement) || null;
+    return parentFolderNode || null;
   }
 
-  private getLastVisibleDescendant_(): BookmarksFolderNodeElement {
+  /**
+   * @private
+   * @return {BookmarksFolderNodeElement}
+   */
+  getLastVisibleDescendant_() {
     const children = this.getChildFolderNodes_();
     if (!this.isOpen || children.length === 0) {
       return this;
     }
 
-    return children.pop()!.getLastVisibleDescendant_();
+    return children.pop().getLastVisibleDescendant_();
   }
 
-  private selectFolder_() {
+  /** @private */
+  selectFolder_() {
     if (!this.isSelectedFolder_) {
       this.dispatch(selectFolder(this.itemId, this.getState().nodes));
     }
   }
 
-  private onContextMenu_(e: MouseEvent) {
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onContextMenu_(e) {
     e.preventDefault();
     this.selectFolder_();
     BookmarksCommandManagerElement.getInstance().openCommandMenuAtPosition(
         e.clientX, e.clientY, MenuSource.TREE, new Set([this.itemId]));
   }
 
-  private getChildFolderNodes_(): BookmarksFolderNodeElement[] {
-    return Array.from(this.shadowRoot!.querySelectorAll(
-        'bookmarks-folder-node'));
+  /**
+   * @private
+   * @return {!Array<!BookmarksFolderNodeElement>}
+   */
+  getChildFolderNodes_() {
+    return Array.from(this.root.querySelectorAll('bookmarks-folder-node'));
   }
 
   /**
    * Toggles whether the folder is open.
+   * @private
+   * @param {!Event} e
    */
-  private toggleFolder_(e: Event) {
+  toggleFolder_(e) {
     this.dispatch(changeFolderOpen(this.itemId, !this.isOpen));
     e.stopPropagation();
   }
 
-  private preventDefault_(e: Event) {
+  /**
+   * @private
+   * @param {!Event} e
+   */
+  preventDefault_(e) {
     e.preventDefault();
   }
 
-  private computeIsSelected_(
-      itemId: string, selectedFolder: string, searchActive: boolean): boolean {
+  /**
+   * @private
+   * @param {string} itemId
+   * @param {string} selectedFolder
+   * @return {boolean}
+   */
+  computeIsSelected_(itemId, selectedFolder, searchActive) {
     return itemId === selectedFolder && !searchActive;
   }
 
-  private computeHasChildFolder_(): boolean {
+  /**
+   * @private
+   * @return {boolean}
+   */
+  computeHasChildFolder_() {
     return hasChildFolders(this.itemId, this.getState().nodes);
   }
 
-  private depthChanged_() {
+  /** @private */
+  depthChanged_() {
     this.style.setProperty('--node-depth', String(this.depth));
     if (this.depth === -1) {
       this.$.descendants.removeAttribute('role');
     }
   }
 
-  private getChildDepth_(): number {
+  /**
+   * @private
+   * @return {number}
+   */
+  getChildDepth_() {
     return this.depth + 1;
   }
 
-  private isFolder_(itemId: string): boolean {
-    return !this.getState().nodes[itemId]!.url;
+  /**
+   * @param {string} itemId
+   * @private
+   * @return {boolean}
+   */
+  isFolder_(itemId) {
+    return !this.getState().nodes[itemId].url;
   }
 
-  private isRootFolder_(): boolean {
+  /**
+   * @private
+   * @return {boolean}
+   */
+  isRootFolder_() {
     return this.itemId === ROOT_NODE_ID;
   }
 
-  private getTabIndex_(): string {
+  /**
+   * @private
+   * @return {string}
+   */
+  getTabIndex_() {
     // This returns a tab index of 0 for the cached selected folder when the
     // search is active, even though this node is not technically selected. This
     // allows the sidebar to be focusable during a search.
@@ -359,8 +421,11 @@
   /**
    * Sets the 'aria-expanded' accessibility on nodes which need it. Note that
    * aria-expanded="false" is different to having the attribute be undefined.
+   * @param {boolean} hasChildFolder
+   * @param {boolean} isOpen
+   * @private
    */
-  private updateAriaExpanded_(hasChildFolder: boolean, isOpen: boolean) {
+  updateAriaExpanded_(hasChildFolder, isOpen) {
     if (hasChildFolder) {
       this.getFocusTarget().setAttribute('aria-expanded', String(isOpen));
     } else {
@@ -370,16 +435,22 @@
 
   /**
    * Scrolls the folder node into view when the folder is selected.
+   * @private
    */
-  private scrollIntoViewIfNeeded_() {
+  scrollIntoViewIfNeeded_() {
     if (!this.isSelectedFolder_) {
       return;
     }
 
-    microTask.run(() => this.$.container.scrollIntoView());
+    microTask.run(() => this.$.container.scrollIntoViewIfNeeded());
   }
 
-  private computeIsOpen_(openState: boolean|null, depth: number): boolean {
+  /**
+   * @param {?boolean} openState
+   * @param {number} depth
+   * @return {boolean}
+   */
+  computeIsOpen_(openState, depth) {
     return openState != null ? openState :
                                depth <= FOLDER_OPEN_BY_DEFAULT_DEPTH;
   }
diff --git a/chrome/browser/resources/bookmarks/item.ts b/chrome/browser/resources/bookmarks/item.js
similarity index 70%
rename from chrome/browser/resources/bookmarks/item.ts
rename to chrome/browser/resources/bookmarks/item.js
index 1d79302..2a0ee7e 100644
--- a/chrome/browser/resources/bookmarks/item.ts
+++ b/chrome/browser/resources/bookmarks/item.js
@@ -8,11 +8,11 @@
 import './shared_style.js';
 import './strings.m.js';
 
-import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {isMac} from 'chrome://resources/js/cr.m.js';
 import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
 import {getFaviconForPageURL} from 'chrome://resources/js/icon.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -23,19 +23,16 @@
 import {BookmarksStoreClientInterface, StoreClient} from './store_client.js';
 import {BookmarkNode, BookmarksPageState} from './types.js';
 
-const BookmarksItemElementBase =
-    mixinBehaviors(StoreClient, PolymerElement) as {
-  new (): PolymerElement & BookmarksStoreClientInterface &
-      StoreObserver<BookmarksPageState>
-}
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ */
+const BookmarksItemElementBase = mixinBehaviors(StoreClient, PolymerElement);
 
-export interface BookmarksItemElement {
-  $: {
-    icon: HTMLDivElement,
-    menuButton: CrIconButtonElement,
-  }
-}
-
+/** @polymer */
 export class BookmarksItemElement extends BookmarksItemElementBase {
   static get is() {
     return 'bookmarks-item';
@@ -51,28 +48,32 @@
         type: String,
         observer: 'onItemIdChanged_',
       },
+
       ironListTabIndex: Number,
+
+      /** @private {BookmarkNode} */
       item_: {
         type: Object,
         observer: 'onItemChanged_',
       },
+
+      /** @private */
       isSelectedItem_: {
         type: Boolean,
         reflectToAttribute: true,
       },
+
+      /** @private */
       isMultiSelect_: Boolean,
+
+      /** @private */
       isFolder_: Boolean,
+
+      /** @private */
       lastTouchPoints_: Number,
     };
   }
 
-  itemId: string;
-  private item_: BookmarkNode;
-  private isSelectedItem_: boolean;
-  private isMultiSelect_: boolean;
-  private isFolder_: boolean;
-  private lastTouchPoints_: number;
-
   static get observers() {
     return [
       'updateFavicon_(item_.url)',
@@ -82,31 +83,43 @@
   ready() {
     super.ready();
 
-    this.addEventListener('click', e => this.onClick_(e as MouseEvent));
-    this.addEventListener('dblclick', e => this.onDblClick_(e as MouseEvent));
+    this.addEventListener(
+        'click',
+        e => this.onClick_(
+            /** @type {!MouseEvent} */ (e)));
+    this.addEventListener(
+        'dblclick',
+        e => this.onDblClick_(
+            /** @type {!MouseEvent} */ (e)));
     this.addEventListener('contextmenu', e => this.onContextMenu_(e));
-    this.addEventListener('keydown', e => this.onKeydown_(e as KeyboardEvent));
     this.addEventListener(
-        'auxclick', e => this.onMiddleClick_(e as MouseEvent));
+        'keydown',
+        e => this.onKeydown_(
+            /** @type {!KeyboardEvent} */ (e)));
     this.addEventListener(
-        'mousedown', e => this.cancelMiddleMouseBehavior_(e as MouseEvent));
+        'auxclick',
+        e => this.onMiddleClick_(
+            /** @type {!MouseEvent} */ (e)));
     this.addEventListener(
-        'mouseup', e => this.cancelMiddleMouseBehavior_(e as MouseEvent));
+        'mousedown',
+        e => this.cancelMiddleMouseBehavior_(
+            /** @type {!MouseEvent} */ (e)));
     this.addEventListener(
-        'touchstart', e => this.onTouchStart_(e as TouchEvent));
+        'mouseup',
+        e => this.cancelMiddleMouseBehavior_(
+            /** @type {!MouseEvent} */ (e)));
+    this.addEventListener(
+        'touchstart',
+        e => this.onTouchStart_(
+            /** @type {!TouchEvent} */ (e)));
   }
 
   connectedCallback() {
     super.connectedCallback();
-    this.watch('item_', state => {
-      return (state as BookmarksPageState).nodes[this.itemId];
-    });
-    this.watch('isSelectedItem_', state => {
-      return (state as BookmarksPageState).selection.items.has(this.itemId);
-    });
-    this.watch('isMultiSelect_', state => {
-      return (state as BookmarksPageState).selection.items.size > 1;
-    });
+    this.watch('item_', store => store.nodes[this.itemId]);
+    this.watch(
+        'isSelectedItem_', store => store.selection.items.has(this.itemId));
+    this.watch('isMultiSelect_', store => store.selection.items.size > 1);
 
     this.updateFromStore();
   }
@@ -115,20 +128,22 @@
     focusWithoutInk(this.$.menuButton);
   }
 
-  getDropTarget(): BookmarksItemElement {
+  /** @return {BookmarksItemElement} */
+  getDropTarget() {
     return this;
   }
 
-  private onContextMenu_(e: MouseEvent) {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onContextMenu_(e) {
     e.preventDefault();
     e.stopPropagation();
 
     // Prevent context menu from appearing after a drag, but allow opening the
     // context menu through 2 taps
-    const capabilities = (e as unknown as {
-                           sourceCapabilities: {firesTouchEvents?: boolean}
-                         }).sourceCapabilities;
-    if (capabilities && capabilities.firesTouchEvents &&
+    if (e.sourceCapabilities && e.sourceCapabilities.firesTouchEvents &&
         this.lastTouchPoints_ !== 2) {
       return;
     }
@@ -150,7 +165,11 @@
     }));
   }
 
-  private onMenuButtonClick_(e: Event) {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onMenuButtonClick_(e) {
     e.stopPropagation();
     e.preventDefault();
 
@@ -170,7 +189,8 @@
     }));
   }
 
-  private selectThisItem_() {
+  /** @private */
+  selectThisItem_() {
     this.dispatch(selectItem(this.itemId, this.getState(), {
       clear: true,
       range: false,
@@ -178,14 +198,16 @@
     }));
   }
 
-  private onItemIdChanged_() {
+  /** @private */
+  onItemIdChanged_() {
     // TODO(tsergeant): Add a histogram to measure whether this assertion fails
     // for real users.
     assert(this.getState().nodes[this.itemId]);
     this.updateFromStore();
   }
 
-  private onItemChanged_() {
+  /** @private */
+  onItemChanged_() {
     this.isFolder_ = !this.item_.url;
     this.setAttribute(
         'aria-label',
@@ -193,7 +215,11 @@
             loadTimeData.getString('folderLabel'));
   }
 
-  private onClick_(e: MouseEvent) {
+  /**
+   * @param {MouseEvent} e
+   * @private
+   */
+  onClick_(e) {
     // Ignore double clicks so that Ctrl double-clicking an item won't deselect
     // the item before opening.
     if (e.detail !== 2) {
@@ -208,7 +234,11 @@
     e.preventDefault();
   }
 
-  private onKeydown_(e: KeyboardEvent) {
+  /**
+   * @private
+   * @param {KeyboardEvent} e
+   */
+  onKeydown_(e) {
     if (e.key === 'ArrowLeft') {
       this.focus();
     } else if (e.key === 'ArrowRight') {
@@ -222,7 +252,11 @@
     }
   }
 
-  private onDblClick_(e: MouseEvent) {
+  /**
+   * @param {MouseEvent} e
+   * @private
+   */
+  onDblClick_(e) {
     if (!this.isSelectedItem_) {
       this.selectThisItem_();
     }
@@ -234,7 +268,11 @@
     }
   }
 
-  private onMiddleClick_(e: MouseEvent) {
+  /**
+   * @param {MouseEvent} e
+   * @private
+   */
+  onMiddleClick_(e) {
     if (e.button !== 1) {
       return;
     }
@@ -252,27 +290,41 @@
     }
   }
 
-  private onTouchStart_(e: TouchEvent) {
+  /**
+   * @param {TouchEvent} e
+   * @private
+   */
+  onTouchStart_(e) {
     this.lastTouchPoints_ = e.touches.length;
   }
 
   /**
    * Prevent default middle-mouse behavior. On Windows, this prevents autoscroll
    * (during mousedown), and on Linux this prevents paste (during mouseup).
+   * @param {MouseEvent} e
+   * @private
    */
-  private cancelMiddleMouseBehavior_(e: MouseEvent) {
+  cancelMiddleMouseBehavior_(e) {
     if (e.button === 1) {
       e.preventDefault();
     }
   }
 
-  private updateFavicon_(url: string) {
+  /**
+   * @param {string} url
+   * @private
+   */
+  updateFavicon_(url) {
     this.$.icon.className = url ? 'website-icon' : 'folder-icon';
     this.$.icon.style.backgroundImage =
         url ? getFaviconForPageURL(url, false) : '';
   }
 
-  private getButtonAriaLabel_(): string {
+  /**
+   * @return {string}
+   * @private
+   */
+  getButtonAriaLabel_() {
     if (!this.item_) {
       return '';  // Item hasn't loaded, skip for now.
     }
@@ -287,8 +339,10 @@
 
   /**
    * This item is part of a group selection.
+   * @return {boolean}
+   * @private
    */
-  private isMultiSelectMenu_(): boolean {
+  isMultiSelectMenu_() {
     return this.isSelectedItem_ && this.isMultiSelect_;
   }
 }
diff --git a/chrome/browser/resources/bookmarks/list.ts b/chrome/browser/resources/bookmarks/list.js
similarity index 72%
rename from chrome/browser/resources/bookmarks/list.ts
rename to chrome/browser/resources/bookmarks/list.js
index 576cebf5..8f3603e 100644
--- a/chrome/browser/resources/bookmarks/list.ts
+++ b/chrome/browser/resources/bookmarks/list.js
@@ -6,18 +6,16 @@
 import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import './shared_style.js';
 import './strings.m.js';
-import './item.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.m.js';
 import {isMac} from 'chrome://resources/js/cr.m.js';
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
-import {ListPropertyUpdateBehavior} from 'chrome://resources/js/list_property_update_behavior.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
+import {ListPropertyUpdateBehavior, ListPropertyUpdateBehaviorInterface} from 'chrome://resources/js/list_property_update_behavior.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
-import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {afterNextRender, html, microTask, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {deselectItems, selectAll, selectItem, updateAnchor} from './actions.js';
@@ -25,23 +23,21 @@
 import {MenuSource} from './constants.js';
 import {BookmarksItemElement} from './item.js';
 import {BookmarksStoreClientInterface, StoreClient} from './store_client.js';
-import {BookmarksPageState, OpenCommandMenuDetail} from './types.js';
+import {BookmarksPageState} from './types.js';
 import {canReorderChildren, getDisplayedList} from './util.js';
 
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ * @implements {ListPropertyUpdateBehaviorInterface}
+ */
 const BookmarksListElementBase =
-    mixinBehaviors([StoreClient, ListPropertyUpdateBehavior], PolymerElement) as
-{
-  new (): PolymerElement &BookmarksStoreClientInterface &
-      StoreObserver<BookmarksPageState> & ListPropertyUpdateBehavior
-}
+    mixinBehaviors([StoreClient, ListPropertyUpdateBehavior], PolymerElement);
 
-export interface BookmarksListElement {
-  $: {
-    list: IronListElement,
-    message: HTMLDivElement,
-  }
-}
-
+/** @polymer */
 export class BookmarksListElement extends BookmarksListElementBase {
   static get is() {
     return 'bookmarks-list';
@@ -57,6 +53,7 @@
        * A list of item ids wrapped in an Object. This is necessary because
        * iron-list is unable to distinguish focusing index 6 from focusing id
        * '6' so the item we supply to iron-list needs to be non-index-like.
+       * @private {Array<{id: string}>}
        */
       displayedList_: {
         type: Array,
@@ -67,68 +64,63 @@
         },
       },
 
+      /** @private {Array<string>} */
       displayedIds_: {
         type: Array,
         observer: 'onDisplayedIdsChanged_',
       },
 
+      /** @private */
       searchTerm_: {
         type: String,
         observer: 'onDisplayedListSourceChange_',
       },
 
+      /** @private */
       selectedFolder_: {
         type: String,
         observer: 'onDisplayedListSourceChange_',
       },
 
+      /** @private {Set<string>} */
       selectedItems_: Object,
     };
   }
 
-  private displayedList_: {id: string}[];
-  private displayedIds_: string[];
-  private eventTracker_: EventTracker = new EventTracker();
-  private searchTerm_: string;
-  private selectedFolder_: string;
-  private selectedItems_: Set<string>;
-  private boundOnHighlightItems_: (p1: CustomEvent) => void;
-
   ready() {
     super.ready();
     this.addEventListener('click', () => this.deselectItems_());
     this.addEventListener('contextmenu', e => this.onContextMenu_(e));
     this.addEventListener(
         'open-command-menu',
-        e => this.onOpenCommandMenu_(e as CustomEvent<OpenCommandMenuDetail>));
+        e => this.onOpenCommandMenu_(
+            /** @type {!CustomEvent<{source: !MenuSource}>} */ (e)));
   }
 
   connectedCallback() {
     super.connectedCallback();
 
-    const list = this.$.list;
+    const list = /** @type {IronListElement} */ (this.$.list);
     list.scrollTarget = this;
 
     this.watch('displayedIds_', function(state) {
-      return getDisplayedList(state as BookmarksPageState);
+      return getDisplayedList(/** @type {!BookmarksPageState} */ (state));
     });
     this.watch('searchTerm_', function(state) {
-      return (state as BookmarksPageState).search.term;
+      return state.search.term;
     });
     this.watch('selectedFolder_', function(state) {
-      return (state as BookmarksPageState).selectedFolder;
+      return state.selectedFolder;
     });
-    this.watch('selectedItems_', function(state) {
-      return (state as BookmarksPageState).selection.items;
-    });
+    this.watch('selectedItems_', ({selection: {items}}) => items);
     this.updateFromStore();
 
     this.$.list.addEventListener(
         'keydown', this.onItemKeydown_.bind(this), true);
 
-    this.eventTracker_.add(
-        document, 'highlight-items',
-        e => this.onHighlightItems_(e as CustomEvent<string[]>));
+    /** @private {function(!Event)} */
+    this.boundOnHighlightItems_ = this.onHighlightItems_.bind(this);
+    document.addEventListener('highlight-items', this.boundOnHighlightItems_);
 
     afterNextRender(this, function() {
       IronA11yAnnouncer.requestAvailability();
@@ -138,19 +130,23 @@
   disconnectedCallback() {
     super.disconnectedCallback();
 
-    this.eventTracker_.remove(document, 'highlight-items');
+    document.removeEventListener(
+        'highlight-items', this.boundOnHighlightItems_);
   }
 
-  getDropTarget(): HTMLElement {
-    return this.$.message;
+  /** @return {HTMLElement} */
+  getDropTarget() {
+    return /** @type {!HTMLDivElement} */ (this.$.message);
   }
 
   /**
    * Updates `displayedList_` using splices to be equivalent to `newValue`. This
    * allows the iron-list to delete sublists of items which preserves scroll and
    * focus on incremental update.
+   * @param {Array<string>} newValue
+   * @param {Array<string>} oldValue
    */
-  private async onDisplayedIdsChanged_(newValue: string[], oldValue: string[]) {
+  async onDisplayedIdsChanged_(newValue, oldValue) {
     const updatedList = newValue.map(id => ({id: id}));
     let skipFocus = false;
     let selectIndex = -1;
@@ -167,8 +163,7 @@
         selectIndex = Math.min(selectIndex, updatedList.length - 1);
       }
     }
-    this.updateList(
-        'displayedList_', item => (item as {id: string}).id, updatedList);
+    this.updateList('displayedList_', item => item.id, updatedList);
     // Trigger a layout of the iron list. Otherwise some elements may render
     // as blank entries. See https://crbug.com/848683
     this.$.list.dispatchEvent(
@@ -185,20 +180,23 @@
         // Focus menu button so 'Undo' is only one tab stop away on delete.
         const item = getDeepActiveElement();
         if (item) {
-          (item as BookmarksItemElement).focusMenuButton();
+          item.focusMenuButton();
         }
       });
     }
   }
 
-  private onDisplayedListSourceChange_() {
+  /** @private */
+  onDisplayedListSourceChange_() {
     this.scrollTop = 0;
   }
 
   /**
    * Scroll the list so that |itemId| is visible, if it is not already.
+   * @param {string} itemId
+   * @private
    */
-  private scrollToId_(itemId: string) {
+  scrollToId_(itemId) {
     const index = this.displayedIds_.indexOf(itemId);
     const list = this.$.list;
     if (index >= 0 && index < list.firstVisibleIndex ||
@@ -207,7 +205,8 @@
     }
   }
 
-  private emptyListMessage_(): string {
+  /** @private */
+  emptyListMessage_() {
     let emptyListMessage = 'noSearchResults';
     if (!this.searchTerm_) {
       emptyListMessage =
@@ -218,42 +217,54 @@
     return loadTimeData.getString(emptyListMessage);
   }
 
-  private isEmptyList_(): boolean {
+  /** @private */
+  isEmptyList_() {
     return this.displayedList_.length === 0;
   }
 
-  private deselectItems_() {
+  /** @private */
+  deselectItems_() {
     this.dispatch(deselectItems());
   }
 
-  private getIndexForItemElement_(el: HTMLElement): number {
-    return (this.$.list.modelForElement(el) as unknown as {index: number})
-        .index;
+  /**
+   * @param{HTMLElement} el
+   * @private
+   */
+  getIndexForItemElement_(el) {
+    return this.$.list.modelForElement(el).index;
   }
 
-  private onOpenCommandMenu_(e: CustomEvent<{source: MenuSource}>) {
+  /**
+   * @param {!CustomEvent<{source: !MenuSource}>} e
+   * @private
+   */
+  onOpenCommandMenu_(e) {
     // If the item is not visible, scroll to it before rendering the menu.
     if (e.detail.source === MenuSource.ITEM) {
-      this.scrollToId_((e.composedPath()[0] as BookmarksItemElement).itemId);
+      this.scrollToId_(
+          /** @type {BookmarksItemElement} */ (e.composedPath()[0]).itemId);
     }
   }
 
   /**
    * Highlight a list of items by selecting them, scrolling them into view and
    * focusing the first item.
+   * @param {Event} e
+   * @private
    */
-  private onHighlightItems_(e: CustomEvent<string[]>) {
+  onHighlightItems_(e) {
     // Ensure that we only select items which are actually being displayed.
     // This should only matter if an unrelated update to the bookmark model
     // happens with the perfect timing to end up in a tracked batch update.
-    const toHighlight =
-        e.detail.filter((item) => this.displayedIds_.indexOf(item) !== -1);
+    const toHighlight = /** @type {!Array<string>} */
+        (e.detail.filter((item) => this.displayedIds_.indexOf(item) !== -1));
 
     if (toHighlight.length <= 0) {
       return;
     }
 
-    const leadId = toHighlight[0]!;
+    const leadId = toHighlight[0];
     this.dispatch(selectAll(toHighlight, this.getState(), leadId));
 
     // Allow iron-list time to render additions to the list.
@@ -265,11 +276,16 @@
     });
   }
 
-  private onItemKeydown_(e: KeyboardEvent) {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onItemKeydown_(e) {
     let handled = true;
     const list = this.$.list;
     let focusMoved = false;
-    let focusedIndex = this.getIndexForItemElement_(e.target as HTMLElement);
+    let focusedIndex =
+        this.getIndexForItemElement_(/** @type {HTMLElement} */ (e.target));
     const oldFocusedIndex = focusedIndex;
     const cursorModifier = isMac ? e.metaKey : e.ctrlKey;
     if (e.key === 'ArrowUp') {
@@ -283,11 +299,11 @@
       focusedIndex = 0;
       focusMoved = true;
     } else if (e.key === 'End') {
-      focusedIndex = list.items!.length - 1;
+      focusedIndex = list.items.length - 1;
       focusMoved = true;
     } else if (e.key === ' ' && cursorModifier) {
       this.dispatch(
-          selectItem(this.displayedIds_[focusedIndex]!, this.getState(), {
+          selectItem(this.displayedIds_[focusedIndex], this.getState(), {
             clear: false,
             range: false,
             toggle: true,
@@ -297,16 +313,15 @@
     }
 
     if (focusMoved) {
-      focusedIndex = Math.min(list.items!.length - 1,
-                              Math.max(0, focusedIndex));
+      focusedIndex = Math.min(list.items.length - 1, Math.max(0, focusedIndex));
       list.focusItem(focusedIndex);
 
       if (cursorModifier && !e.shiftKey) {
-        this.dispatch(updateAnchor(this.displayedIds_[focusedIndex]!));
+        this.dispatch(updateAnchor(this.displayedIds_[focusedIndex]));
       } else {
         // If shift-selecting with no anchor, use the old focus index.
         if (e.shiftKey && this.getState().selection.anchor === null) {
-          this.dispatch(updateAnchor(this.displayedIds_[oldFocusedIndex]!));
+          this.dispatch(updateAnchor(this.displayedIds_[oldFocusedIndex]));
         }
 
         // If the focus moved from something other than a Ctrl + move event,
@@ -318,13 +333,13 @@
         };
 
         this.dispatch(selectItem(
-            this.displayedIds_[focusedIndex]!, this.getState(), config));
+            this.displayedIds_[focusedIndex], this.getState(), config));
       }
     }
 
     // Prevent the iron-list from changing focus on enter.
     if (e.key === 'Enter') {
-      if ((e.composedPath()[0] as HTMLElement).tagName === 'CR-ICON-BUTTON') {
+      if (e.composedPath()[0].tagName === 'CR-ICON-BUTTON') {
         return;
       }
       if (e.composedPath()[0] instanceof HTMLButtonElement) {
@@ -342,7 +357,11 @@
     }
   }
 
-  private onContextMenu_(e: MouseEvent) {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onContextMenu_(e) {
     e.preventDefault();
     this.deselectItems_();
 
@@ -357,11 +376,21 @@
     }));
   }
 
-  private getAriaRowindex_(index: number): number {
+  /**
+   * Returns a 1-based index for aria-rowindex.
+   * @param {number} index
+   * @return {number}
+   * @private
+   */
+  getAriaRowindex_(index) {
     return index + 1;
   }
 
-  private getAriaSelected_(id: string): boolean {
+  /**
+   * @param {string} id
+   * @return {boolean}
+   */
+  getAriaSelected_(id) {
     return this.selectedItems_.has(id);
   }
 }
diff --git a/chrome/browser/resources/bookmarks/mouse_focus_behavior.js b/chrome/browser/resources/bookmarks/mouse_focus_behavior.js
new file mode 100644
index 0000000..6740996
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/mouse_focus_behavior.js
@@ -0,0 +1,46 @@
+// Copyright 2017 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.
+
+/** @const */
+export const HIDE_FOCUS_RING_ATTRIBUTE = 'hide-focus-ring';
+
+/**
+ * Behavior which adds the 'hide-focus-ring' attribute to a target element
+ * when the user interacts with it using the mouse, allowing the focus outline
+ * to be hidden without affecting keyboard users.
+ * @polymerBehavior
+ */
+export const MouseFocusBehavior = {
+  attached() {
+    this.boundOnMousedown_ = this.onMousedown_.bind(this);
+    this.boundOnKeydown = this.onKeydown_.bind(this);
+
+    // These events are added to the document because capture doesn't work
+    // properly when listeners are added to a Polymer element, because the
+    // event is considered AT_TARGET for the element, and is evaluated after
+    // inner captures.
+    document.addEventListener('mousedown', this.boundOnMousedown_, true);
+    document.addEventListener('keydown', this.boundOnKeydown, true);
+  },
+
+  detached() {
+    document.removeEventListener('mousedown', this.boundOnMousedown_, true);
+    document.removeEventListener('keydown', this.boundOnKeydown, true);
+  },
+
+  /** @private */
+  onMousedown_() {
+    this.setAttribute(HIDE_FOCUS_RING_ATTRIBUTE, '');
+  },
+
+  /**
+   * @param {KeyboardEvent} e
+   * @private
+   */
+  onKeydown_(e) {
+    if (!['Shift', 'Alt', 'Control', 'Meta'].includes(e.key)) {
+      this.removeAttribute(HIDE_FOCUS_RING_ATTRIBUTE);
+    }
+  },
+};
diff --git a/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts b/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts
deleted file mode 100644
index 5d266336..0000000
--- a/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2017 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 {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-export const HIDE_FOCUS_RING_ATTRIBUTE = 'hide-focus-ring';
-
-type Constructor<T> = new ( ...args: any[]) => T;
-
-/**
- * Behavior which adds the 'hide-focus-ring' attribute to a target element
- * when the user interacts with it using the mouse, allowing the focus outline
- * to be hidden without affecting keyboard users.
- */
-export const MouseFocusMixin = dedupingMixin(
-    <T extends Constructor<PolymerElement>>(superClass: T): T&
-    Constructor<MouseFocusMixinInterface> => {
-      class MouseFocusMixin extends superClass {
-        private boundOnMousedown_: (e: Event) => void;
-        boundOnKeydown: (e: KeyboardEvent) => void;
-
-        connectedCallback() {
-          super.connectedCallback();
-          this.boundOnMousedown_ = this.onMousedown_.bind(this);
-          this.boundOnKeydown = this.onKeydown_.bind(this);
-
-          // These events are added to the document because capture doesn't work
-          // properly when listeners are added to a Polymer element, because the
-          // event is considered AT_TARGET for the element, and is evaluated
-          // after inner captures.
-          document.addEventListener('mousedown', this.boundOnMousedown_, true);
-          document.addEventListener('keydown', this.boundOnKeydown, true);
-        }
-
-        disconnectedCallback() {
-          super.disconnectedCallback();
-          document.removeEventListener(
-              'mousedown', this.boundOnMousedown_, true);
-          document.removeEventListener(
-              'keydown', this.boundOnKeydown, true);
-        }
-
-        private onMousedown_() {
-          this.setAttribute(HIDE_FOCUS_RING_ATTRIBUTE, '');
-        }
-
-        private onKeydown_(e: KeyboardEvent) {
-          if (!['Shift', 'Alt', 'Control', 'Meta'].includes(e.key)) {
-            this.removeAttribute(HIDE_FOCUS_RING_ATTRIBUTE);
-          }
-        }
-      }
-
-      return MouseFocusMixin;
-    });
-
-export interface MouseFocusMixinInterface {
-  boundOnKeydown: (e: KeyboardEvent) => void;
-}
diff --git a/chrome/browser/resources/bookmarks/reducers.js b/chrome/browser/resources/bookmarks/reducers.js
new file mode 100644
index 0000000..ea24531
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/reducers.js
@@ -0,0 +1,468 @@
+// Copyright 2017 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 {assert} from 'chrome://resources/js/assert.m.js';
+
+import {BookmarkNode, BookmarksPageState, FolderOpenState, NodeMap, PreferencesState, SearchState, SelectionState} from './types.js';
+import {removeIdsFromMap, removeIdsFromObject, removeIdsFromSet} from './util.js';
+
+/**
+ * @fileoverview Module of functions which produce a new page state in response
+ * to an action. Reducers (in the same sense as Array.prototype.reduce) must be
+ * pure functions: they must not modify existing state objects, or make any API
+ * calls.
+ */
+
+/**
+ * @param {SelectionState} selectionState
+ * @param {Object} action
+ * @return {SelectionState}
+ */
+function selectItems(selectionState, action) {
+  let newItems = new Set();
+  if (!action.clear) {
+    newItems = new Set(selectionState.items);
+  }
+
+  action.items.forEach(function(id) {
+    let add = true;
+    if (action.toggle) {
+      add = !newItems.has(id);
+    }
+
+    if (add) {
+      newItems.add(id);
+    } else {
+      newItems.delete(id);
+    }
+  });
+
+  return /** @type {SelectionState} */ (Object.assign({}, selectionState, {
+    items: newItems,
+    anchor: action.anchor,
+  }));
+}
+
+/**
+ * @param {SelectionState} selectionState
+ * @return {SelectionState}
+ */
+function deselectAll(selectionState) {
+  return {
+    items: new Set(),
+    anchor: null,
+  };
+}
+
+/**
+ * @param {SelectionState} selectionState
+ * @param {!Set<string>} deleted
+ * @return SelectionState
+ */
+function deselectItems(selectionState, deleted) {
+  return /** @type {SelectionState} */ (Object.assign({}, selectionState, {
+    items: removeIdsFromSet(selectionState.items, deleted),
+    anchor: !selectionState.anchor || deleted.has(selectionState.anchor) ?
+        null :
+        selectionState.anchor,
+  }));
+}
+
+/**
+ * @param {SelectionState} selectionState
+ * @param {Object} action
+ * @return {SelectionState}
+ */
+function updateAnchor(selectionState, action) {
+  return /** @type {SelectionState} */ (Object.assign({}, selectionState, {
+    anchor: action.anchor,
+  }));
+}
+
+/**
+ * Exported for tests.
+ * @param {SelectionState} selection
+ * @param {Object} action
+ * @return {SelectionState}
+ */
+export function updateSelection(selection, action) {
+  switch (action.name) {
+    case 'clear-search':
+    case 'finish-search':
+    case 'select-folder':
+    case 'deselect-items':
+      return deselectAll(selection);
+    case 'select-items':
+      return selectItems(selection, action);
+    case 'remove-bookmark':
+      return deselectItems(selection, action.descendants);
+    case 'move-bookmark':
+      // Deselect items when they are moved to another folder, since they will
+      // no longer be visible on screen (for simplicity, ignores items visible
+      // in search results).
+      if (action.parentId !== action.oldParentId &&
+          selection.items.has(action.id)) {
+        return deselectItems(selection, new Set([action.id]));
+      }
+      return selection;
+    case 'update-anchor':
+      return updateAnchor(selection, action);
+    default:
+      return selection;
+  }
+}
+
+/**
+ * @param {SearchState} search
+ * @param {Object} action
+ * @return {SearchState}
+ */
+function startSearch(search, action) {
+  return {
+    term: action.term,
+    inProgress: true,
+    results: search.results,
+  };
+}
+
+/**
+ * @param {SearchState} search
+ * @param {Object} action
+ * @return {SearchState}
+ */
+function finishSearch(search, action) {
+  return /** @type {SearchState} */ (Object.assign({}, search, {
+    inProgress: false,
+    results: action.results,
+  }));
+}
+
+/** @return {SearchState} */
+function clearSearch() {
+  return {
+    term: '',
+    inProgress: false,
+    results: null,
+  };
+}
+
+/**
+ * @param {SearchState} search
+ * @param {!Set<string>} deletedIds
+ * @return {SearchState}
+ */
+function removeDeletedResults(search, deletedIds) {
+  if (!search.results) {
+    return search;
+  }
+
+  const newResults = [];
+  search.results.forEach(function(id) {
+    if (!deletedIds.has(id)) {
+      newResults.push(id);
+    }
+  });
+  return /** @type {SearchState} */ (Object.assign({}, search, {
+    results: newResults,
+  }));
+}
+
+/**
+ * @param {SearchState} search
+ * @param {Object} action
+ * @return {SearchState}
+ */
+function updateSearch(search, action) {
+  switch (action.name) {
+    case 'start-search':
+      return startSearch(search, action);
+    case 'select-folder':
+    case 'clear-search':
+      return clearSearch();
+    case 'finish-search':
+      return finishSearch(search, action);
+    case 'remove-bookmark':
+      return removeDeletedResults(search, action.descendants);
+    default:
+      return search;
+  }
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {string} id
+ * @param {function(BookmarkNode):BookmarkNode} callback
+ * @return {NodeMap}
+ */
+function modifyNode(nodes, id, callback) {
+  const nodeModification = {};
+  nodeModification[id] = callback(nodes[id]);
+  return Object.assign({}, nodes, nodeModification);
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {Object} action
+ * @return {NodeMap}
+ */
+function createBookmark(nodes, action) {
+  const nodeModifications = {};
+  nodeModifications[action.id] = action.node;
+
+  const parentNode = nodes[action.parentId];
+  const newChildren = parentNode.children.slice();
+  newChildren.splice(action.parentIndex, 0, action.id);
+  nodeModifications[action.parentId] = Object.assign({}, parentNode, {
+    children: newChildren,
+  });
+
+  return Object.assign({}, nodes, nodeModifications);
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {Object} action
+ * @return {NodeMap}
+ */
+function editBookmark(nodes, action) {
+  // Do not allow folders to change URL (making them no longer folders).
+  if (!nodes[action.id].url && action.changeInfo.url) {
+    delete action.changeInfo.url;
+  }
+
+  return modifyNode(nodes, action.id, function(node) {
+    return /** @type {BookmarkNode} */ (
+        Object.assign({}, node, action.changeInfo));
+  });
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {Object} action
+ * @return {NodeMap}
+ */
+function moveBookmark(nodes, action) {
+  const nodeModifications = {};
+  const id = action.id;
+
+  // Change node's parent.
+  nodeModifications[id] =
+      Object.assign({}, nodes[id], {parentId: action.parentId});
+
+  // Remove from old parent.
+  const oldParentId = action.oldParentId;
+  const oldParentChildren = nodes[oldParentId].children.slice();
+  oldParentChildren.splice(action.oldIndex, 1);
+  nodeModifications[oldParentId] =
+      Object.assign({}, nodes[oldParentId], {children: oldParentChildren});
+
+  // Add to new parent.
+  const parentId = action.parentId;
+  const parentChildren = oldParentId === parentId ?
+      oldParentChildren :
+      nodes[parentId].children.slice();
+  parentChildren.splice(action.index, 0, action.id);
+  nodeModifications[parentId] =
+      Object.assign({}, nodes[parentId], {children: parentChildren});
+
+  return Object.assign({}, nodes, nodeModifications);
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {Object} action
+ * @return {NodeMap}
+ */
+function removeBookmark(nodes, action) {
+  const newState = modifyNode(nodes, action.parentId, function(node) {
+    const newChildren = node.children.slice();
+    newChildren.splice(action.index, 1);
+    return /** @type {BookmarkNode} */ (
+        Object.assign({}, node, {children: newChildren}));
+  });
+
+  return removeIdsFromObject(newState, action.descendants);
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {Object} action
+ * @return {NodeMap}
+ */
+function reorderChildren(nodes, action) {
+  return modifyNode(nodes, action.id, function(node) {
+    return /** @type {BookmarkNode} */ (
+        Object.assign({}, node, {children: action.children}));
+  });
+}
+
+/**
+ * Exported for tests.
+ * @param {NodeMap} nodes
+ * @param {Object} action
+ * @return {NodeMap}
+ */
+export function updateNodes(nodes, action) {
+  switch (action.name) {
+    case 'create-bookmark':
+      return createBookmark(nodes, action);
+    case 'edit-bookmark':
+      return editBookmark(nodes, action);
+    case 'move-bookmark':
+      return moveBookmark(nodes, action);
+    case 'remove-bookmark':
+      return removeBookmark(nodes, action);
+    case 'reorder-children':
+      return reorderChildren(nodes, action);
+    case 'refresh-nodes':
+      return action.nodes;
+    default:
+      return nodes;
+  }
+}
+
+/**
+ * @param {NodeMap} nodes
+ * @param {string} ancestorId
+ * @param {string} childId
+ * @return {boolean}
+ */
+function isAncestorOf(nodes, ancestorId, childId) {
+  let currentId = childId;
+  // Work upwards through the tree from child.
+  while (currentId) {
+    if (currentId === ancestorId) {
+      return true;
+    }
+    currentId = nodes[currentId].parentId;
+  }
+  return false;
+}
+
+/**
+ * Exported for tests.
+ * @param {string} selectedFolder
+ * @param {Object} action
+ * @param {NodeMap} nodes
+ * @return {string}
+ */
+export function updateSelectedFolder(selectedFolder, action, nodes) {
+  switch (action.name) {
+    case 'select-folder':
+      return action.id;
+    case 'change-folder-open':
+      // When hiding the selected folder by closing its ancestor, select
+      // that ancestor instead.
+      if (!action.open && selectedFolder &&
+          isAncestorOf(nodes, action.id, selectedFolder)) {
+        return action.id;
+      }
+      return selectedFolder;
+    case 'remove-bookmark':
+      // When deleting the selected folder (or its ancestor), select the
+      // parent of the deleted node.
+      if (selectedFolder && isAncestorOf(nodes, action.id, selectedFolder)) {
+        return assert(nodes[action.id].parentId);
+      }
+      return selectedFolder;
+    default:
+      return selectedFolder;
+  }
+}
+
+/**
+ * @param {FolderOpenState} folderOpenState
+ * @param {string|undefined} id
+ * @param {NodeMap} nodes
+ * @return {FolderOpenState}
+ */
+function openFolderAndAncestors(folderOpenState, id, nodes) {
+  const newFolderOpenState =
+      /** @type {FolderOpenState} */ (new Map(folderOpenState));
+  for (let currentId = id; currentId; currentId = nodes[currentId].parentId) {
+    newFolderOpenState.set(currentId, true);
+  }
+
+  return newFolderOpenState;
+}
+
+/**
+ * @param {FolderOpenState} folderOpenState
+ * @param {Object} action
+ * @return {FolderOpenState}
+ */
+function changeFolderOpen(folderOpenState, action) {
+  const newFolderOpenState =
+      /** @type {FolderOpenState} */ (new Map(folderOpenState));
+  newFolderOpenState.set(action.id, action.open);
+
+  return newFolderOpenState;
+}
+
+/**
+ * Exported for tests.
+ * @param {FolderOpenState} folderOpenState
+ * @param {Object} action
+ * @param {NodeMap} nodes
+ * @return {FolderOpenState}
+ */
+export function updateFolderOpenState(folderOpenState, action, nodes) {
+  switch (action.name) {
+    case 'change-folder-open':
+      return changeFolderOpen(folderOpenState, action);
+    case 'select-folder':
+      return openFolderAndAncestors(
+          folderOpenState, nodes[action.id].parentId, nodes);
+    case 'move-bookmark':
+      if (!nodes[action.id].children) {
+        return folderOpenState;
+      }
+
+      return openFolderAndAncestors(folderOpenState, action.parentId, nodes);
+    case 'remove-bookmark':
+      return removeIdsFromMap(folderOpenState, action.descendants);
+    default:
+      return folderOpenState;
+  }
+}
+
+/**
+ * @param {PreferencesState} prefs
+ * @param {Object} action
+ * @return {PreferencesState}
+ */
+function updatePrefs(prefs, action) {
+  switch (action.name) {
+    case 'set-incognito-availability':
+      return /** @type {PreferencesState} */ (Object.assign({}, prefs, {
+        incognitoAvailability: action.value,
+      }));
+    case 'set-can-edit':
+      return /** @type {PreferencesState} */ (Object.assign({}, prefs, {
+        canEdit: action.value,
+      }));
+    default:
+      return prefs;
+  }
+}
+
+/**
+ * Root reducer for the Bookmarks page. This is called by the store in
+ * response to an action, and the return value is used to update the UI.
+ * @param {!BookmarksPageState} state
+ * @param {Object} action
+ * @return {!BookmarksPageState}
+ */
+export function reduceAction(state, action) {
+  return {
+    nodes: updateNodes(state.nodes, action),
+    selectedFolder:
+        updateSelectedFolder(state.selectedFolder, action, state.nodes),
+    folderOpenState:
+        updateFolderOpenState(state.folderOpenState, action, state.nodes),
+    prefs: updatePrefs(state.prefs, action),
+    search: updateSearch(state.search, action),
+    selection: updateSelection(state.selection, action),
+  };
+}
diff --git a/chrome/browser/resources/bookmarks/reducers.ts b/chrome/browser/resources/bookmarks/reducers.ts
deleted file mode 100644
index 5e22447..0000000
--- a/chrome/browser/resources/bookmarks/reducers.ts
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2017 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.
-
-/**
- * @fileoverview Module of functions which produce a new page state in response
- * to an action. Reducers (in the same sense as Array.prototype.reduce) must be
- * pure functions: they must not modify existing state objects, or make any API
- * calls.
- */
-
-import {assert} from 'chrome://resources/js/assert.m.js';
-import {Action} from 'chrome://resources/js/cr/ui/store.m.js';
-
-import {ChangeFolderOpenAction, CreateBookmarkAction, EditBookmarkAction, FinishSearchAction, MoveBookmarkAction, RefreshNodesAction, RemoveBookmarkAction, ReorderChildrenAction, SelectFolderAction, SelectItemsAction, SetPrefAction, StartSearchAction, UpdateAnchorAction} from './actions.js';
-import {BookmarkNode, BookmarksPageState, FolderOpenState, NodeMap, PreferencesState, SearchState, SelectionState} from './types.js';
-import {removeIdsFromMap, removeIdsFromObject, removeIdsFromSet} from './util.js';
-
-function selectItems(
-    selectionState: SelectionState, action: SelectItemsAction): SelectionState {
-  let newItems = new Set();
-  if (!action.clear) {
-    newItems = new Set(selectionState.items);
-  }
-
-  action.items.forEach(function(id) {
-    let add = true;
-    if (action.toggle) {
-      add = !newItems.has(id);
-    }
-
-    if (add) {
-      newItems.add(id);
-    } else {
-      newItems.delete(id);
-    }
-  });
-
-  return (Object.assign({}, selectionState, {
-    items: newItems,
-    anchor: action.anchor,
-  }) as SelectionState);
-}
-
-function deselectAll(selectionState: SelectionState): SelectionState {
-  return {
-    items: new Set(),
-    anchor: null,
-  };
-}
-
-function deselectItems(
-    selectionState: SelectionState, deleted: Set<string>): SelectionState {
-  return /** @type {SelectionState} */ (Object.assign({}, selectionState, {
-    items: removeIdsFromSet(selectionState.items, deleted),
-    anchor: !selectionState.anchor || deleted.has(selectionState.anchor) ?
-        null :
-        selectionState.anchor,
-  }));
-}
-
-function updateAnchor(
-    selectionState: SelectionState,
-    action: UpdateAnchorAction): SelectionState {
-  return (Object.assign({}, selectionState, {
-    anchor: action.anchor,
-  }) as SelectionState);
-}
-
-// Exported for tests.
-export function updateSelection(
-    selection: SelectionState, action: Action): SelectionState {
-  switch (action.name) {
-    case 'clear-search':
-    case 'finish-search':
-    case 'select-folder':
-    case 'deselect-items':
-      return deselectAll(selection);
-    case 'select-items':
-      return selectItems(selection, action as SelectItemsAction);
-    case 'remove-bookmark':
-      return deselectItems(
-          selection, (action as RemoveBookmarkAction).descendants);
-    case 'move-bookmark':
-      // Deselect items when they are moved to another folder, since they will
-      // no longer be visible on screen (for simplicity, ignores items visible
-      // in search results).
-      const moveAction = action as MoveBookmarkAction;
-      if (moveAction.parentId !== moveAction.oldParentId &&
-          selection.items.has(moveAction.id)) {
-        return deselectItems(selection, new Set([moveAction.id]));
-      }
-      return selection;
-    case 'update-anchor':
-      return updateAnchor(selection, action as UpdateAnchorAction);
-    default:
-      return selection;
-  }
-}
-
-function startSearch(
-    search: SearchState, action: StartSearchAction): SearchState {
-  return {
-    term: action.term,
-    inProgress: true,
-    results: search.results,
-  };
-}
-
-function finishSearch(
-    search: SearchState, action: FinishSearchAction): SearchState {
-  return /** @type {SearchState} */ (Object.assign({}, search, {
-    inProgress: false,
-    results: action.results,
-  }));
-}
-
-function clearSearch(): SearchState {
-  return {
-    term: '',
-    inProgress: false,
-    results: null,
-  };
-}
-
-function removeDeletedResults(
-    search: SearchState, deletedIds: Set<string>): SearchState {
-  if (!search.results) {
-    return search;
-  }
-
-  const newResults: string[] = [];
-  search.results.forEach(function(id) {
-    if (!deletedIds.has(id)) {
-      newResults.push(id);
-    }
-  });
-  return (Object.assign({}, search, {
-    results: newResults,
-  }) as SearchState);
-}
-
-function updateSearch(search: SearchState, action: Action): SearchState {
-  switch (action.name) {
-    case 'start-search':
-      return startSearch(search, action as StartSearchAction);
-    case 'select-folder':
-    case 'clear-search':
-      return clearSearch();
-    case 'finish-search':
-      return finishSearch(search, action as FinishSearchAction);
-    case 'remove-bookmark':
-      return removeDeletedResults(
-          search, (action as RemoveBookmarkAction).descendants);
-    default:
-      return search;
-  }
-}
-
-function modifyNode(
-    nodes: NodeMap, id: string,
-    callback: (p1: BookmarkNode) => BookmarkNode): NodeMap {
-  const nodeModification: NodeMap = {};
-  nodeModification[id] = callback(nodes[id]!);
-  return Object.assign({}, nodes, nodeModification);
-}
-
-function createBookmark(nodes: NodeMap, action: CreateBookmarkAction): NodeMap {
-  const nodeModifications: NodeMap = {};
-  nodeModifications[action.id] = action.node;
-
-  const parentNode = nodes[action.parentId]!;
-  const newChildren = parentNode.children!.slice();
-  newChildren.splice(action.parentIndex, 0, action.id);
-  nodeModifications[action.parentId] = Object.assign({}, parentNode, {
-    children: newChildren,
-  });
-
-  return Object.assign({}, nodes, nodeModifications);
-}
-
-function editBookmark(nodes: NodeMap, action: EditBookmarkAction): NodeMap {
-  // Do not allow folders to change URL (making them no longer folders).
-  if (!nodes[action.id]!.url && action.changeInfo.url) {
-    delete action.changeInfo.url;
-  }
-
-  return modifyNode(nodes, action.id, function(node) {
-    return Object.assign({}, node, action.changeInfo);
-  });
-}
-
-function moveBookmark(nodes: NodeMap, action: MoveBookmarkAction): NodeMap {
-  const nodeModifications: NodeMap = {};
-  const id = action.id;
-
-  // Change node's parent.
-  nodeModifications[id] =
-      Object.assign({}, nodes[id], {parentId: action.parentId});
-
-  // Remove from old parent.
-  const oldParentId = action.oldParentId;
-  const oldParentChildren = nodes[oldParentId]!.children!.slice();
-  oldParentChildren.splice(action.oldIndex, 1);
-  nodeModifications[oldParentId] =
-      Object.assign({}, nodes[oldParentId], {children: oldParentChildren});
-
-  // Add to new parent.
-  const parentId = action.parentId;
-  const parentChildren = oldParentId === parentId ?
-      oldParentChildren :
-      nodes[parentId]!.children!.slice();
-  parentChildren.splice(action.index, 0, action.id);
-  nodeModifications[parentId] =
-      Object.assign({}, nodes[parentId], {children: parentChildren});
-
-  return Object.assign({}, nodes, nodeModifications);
-}
-
-function removeBookmark(nodes: NodeMap, action: RemoveBookmarkAction): NodeMap {
-  const newState = modifyNode(nodes, action.parentId, function(node) {
-    const newChildren = node.children!.slice();
-    newChildren.splice(action.index, 1);
-    return /** @type {BookmarkNode} */ (
-        Object.assign({}, node, {children: newChildren}));
-  });
-
-  return removeIdsFromObject(newState, action.descendants);
-}
-
-function reorderChildren(
-    nodes: NodeMap, action: ReorderChildrenAction): NodeMap {
-  return modifyNode(nodes, action.id, function(node) {
-    return /** @type {BookmarkNode} */ (
-        Object.assign({}, node, {children: action.children}));
-  });
-}
-
-export function updateNodes(nodes: NodeMap, action: Action): NodeMap {
-  switch (action.name) {
-    case 'create-bookmark':
-      return createBookmark(nodes, action as CreateBookmarkAction);
-    case 'edit-bookmark':
-      return editBookmark(nodes, action as EditBookmarkAction);
-    case 'move-bookmark':
-      return moveBookmark(nodes, action as MoveBookmarkAction);
-    case 'remove-bookmark':
-      return removeBookmark(nodes, action as RemoveBookmarkAction);
-    case 'reorder-children':
-      return reorderChildren(nodes, action as ReorderChildrenAction);
-    case 'refresh-nodes':
-      return (action as RefreshNodesAction).nodes;
-    default:
-      return nodes;
-  }
-}
-
-function isAncestorOf(
-    nodes: NodeMap, ancestorId: string, childId: string): boolean {
-  let currentId: string|undefined = childId;
-  // Work upwards through the tree from child.
-  while (currentId) {
-    if (currentId === ancestorId) {
-      return true;
-    }
-    currentId = nodes[currentId!]!.parentId;
-  }
-  return false;
-}
-
-// Exported for tests.
-export function updateSelectedFolder(
-    selectedFolder: string, action: Action, nodes: NodeMap): string {
-  switch (action.name) {
-    case 'select-folder':
-      return (action as SelectFolderAction).id;
-    case 'change-folder-open':
-      // When hiding the selected folder by closing its ancestor, select
-      // that ancestor instead.
-      const changeFolderAction = action as ChangeFolderOpenAction;
-      if (!changeFolderAction.open && selectedFolder &&
-          isAncestorOf(nodes, changeFolderAction.id, selectedFolder)) {
-        return changeFolderAction.id;
-      }
-      return selectedFolder;
-    case 'remove-bookmark':
-      // When deleting the selected folder (or its ancestor), select the
-      // parent of the deleted node.
-      const id = (action as RemoveBookmarkAction).id;
-      if (selectedFolder && isAncestorOf(nodes, id, selectedFolder)) {
-        return assert(nodes[id]!.parentId!);
-      }
-      return selectedFolder;
-    default:
-      return selectedFolder;
-  }
-}
-
-function openFolderAndAncestors(
-    folderOpenState: FolderOpenState, id: string, nodes: NodeMap):
-        FolderOpenState {
-  const newFolderOpenState = (new Map(folderOpenState) as FolderOpenState);
-  for (let currentId = id; currentId; currentId = nodes[currentId]!.parentId!) {
-    newFolderOpenState.set(currentId, true);
-  }
-
-  return newFolderOpenState;
-}
-
-function changeFolderOpen(
-    folderOpenState: FolderOpenState,
-    action: ChangeFolderOpenAction): FolderOpenState {
-  const newFolderOpenState = new Map(folderOpenState) as FolderOpenState;
-  newFolderOpenState.set(action.id, action.open);
-
-  return newFolderOpenState;
-}
-
-export function updateFolderOpenState(
-    folderOpenState: FolderOpenState, action: Action,
-    nodes: NodeMap): FolderOpenState {
-  switch (action.name) {
-    case 'change-folder-open':
-      return changeFolderOpen(
-          folderOpenState, action as ChangeFolderOpenAction);
-    case 'select-folder':
-      return openFolderAndAncestors(
-          folderOpenState, nodes[(action as SelectFolderAction).id]!.parentId!,
-          nodes);
-    case 'move-bookmark':
-      if (!nodes[(action as MoveBookmarkAction).id]!.children) {
-        return folderOpenState;
-      }
-      return openFolderAndAncestors(
-          folderOpenState, (action as MoveBookmarkAction).parentId, nodes);
-    case 'remove-bookmark':
-      return removeIdsFromMap(
-          folderOpenState, (action as RemoveBookmarkAction).descendants);
-    default:
-      return folderOpenState;
-  }
-}
-
-function updatePrefs(
-    prefs: PreferencesState, action: Action): PreferencesState {
-  const prefAction = action as SetPrefAction;
-  switch (prefAction.name) {
-    case 'set-incognito-availability':
-      return /** @type {PreferencesState} */ (Object.assign({}, prefs, {
-        incognitoAvailability: prefAction.value,
-      }));
-    case 'set-can-edit':
-      return /** @type {PreferencesState} */ (Object.assign({}, prefs, {
-        canEdit: prefAction.value,
-      }));
-    default:
-      return prefs;
-  }
-}
-
-export function reduceAction(
-    state: BookmarksPageState, action: Action): BookmarksPageState {
-  return {
-    nodes: updateNodes(state.nodes, action),
-    selectedFolder:
-        updateSelectedFolder(state.selectedFolder, action, state.nodes),
-    folderOpenState:
-        updateFolderOpenState(state.folderOpenState, action, state.nodes),
-    prefs: updatePrefs(state.prefs, action),
-    search: updateSearch(state.search, action),
-    selection: updateSelection(state.selection, action),
-  };
-}
diff --git a/chrome/browser/resources/bookmarks/router.ts b/chrome/browser/resources/bookmarks/router.js
similarity index 70%
rename from chrome/browser/resources/bookmarks/router.ts
rename to chrome/browser/resources/bookmarks/router.js
index 2bac7c4a..6f90ca2e0 100644
--- a/chrome/browser/resources/bookmarks/router.ts
+++ b/chrome/browser/resources/bookmarks/router.js
@@ -6,6 +6,7 @@
 import 'chrome://resources/polymer/v3_0/iron-location/iron-query-params.js';
 
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
 import {Debouncer, html, microTask, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {selectFolder, setSearchTerm} from './actions.js';
@@ -13,16 +14,20 @@
 import {BookmarksStoreClientInterface, StoreClient} from './store_client.js';
 import {BookmarksPageState} from './types.js';
 
-const BookmarksRouterElementBase =
-    mixinBehaviors(StoreClient, PolymerElement) as {
-  new (): PolymerElement & BookmarksStoreClientInterface &
-      StoreObserver<BookmarksPageState>
-}
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ */
+const BookmarksRouterElementBase = mixinBehaviors(StoreClient, PolymerElement);
 
 /**
  * This element is a one way bound interface that routes the page URL to
  * the searchTerm and selectedId. Clients must initialize themselves by
  * reading the router's fields after attach.
+ * @polymer
  */
 export class BookmarksRouterElement extends BookmarksRouterElementBase {
   static get is() {
@@ -35,34 +40,36 @@
 
   static get properties() {
     return {
+      /**
+       * Parameter q is routed to the searchTerm.
+       * Parameter id is routed to the selectedId.
+       * @private
+       */
       queryParams_: Object,
 
+      /** @private {string} */
       query_: {
         type: String,
         observer: 'onQueryChanged_',
       },
 
+      /** @private {string} */
       urlQuery_: {
         type: String,
         observer: 'onUrlQueryChanged_',
       },
 
+      /** @private */
       searchTerm_: {
         type: String,
         value: '',
       },
 
+      /** @private {?string} */
       selectedId_: String,
     };
   }
 
-  private query_: string;
-  private queryParams_: {q?: string, id?: string};
-  private searchTerm_: string = '';
-  private selectedId_: string;
-  private urlQuery_: string;
-  private debounceJob_: Debouncer;
-
   static get observers() {
     return [
       'onQueryParamsChanged_(queryParams_)',
@@ -70,18 +77,25 @@
     ];
   }
 
+  constructor() {
+    super();
+    /** @private {Debouncer} */
+    this.debounceJob_;
+  }
+
   connectedCallback() {
     super.connectedCallback();
-    this.watch('selectedId_', function(state: BookmarksPageState) {
+    this.watch('selectedId_', function(state) {
       return state.selectedFolder;
     });
-    this.watch('searchTerm_', function(state: BookmarksPageState) {
+    this.watch('searchTerm_', function(state) {
       return state.search.term;
     });
     this.updateFromStore();
   }
 
-  private onQueryParamsChanged_() {
+  /** @private */
+  onQueryParamsChanged_() {
     const searchTerm = this.queryParams_.q || '';
     let selectedId = this.queryParams_.id;
     if (!selectedId && !searchTerm) {
@@ -98,27 +112,35 @@
       // Need to dispatch a deferred action so that during page load
       // `this.getState()` will only evaluate after the Store is initialized.
       this.dispatchAsync((dispatch) => {
-        dispatch(selectFolder(selectedId!, this.getState().nodes));
+        dispatch(selectFolder(selectedId, this.getState().nodes));
       });
     }
   }
 
-  private onQueryChanged_(current: (string|null), previous: (string|null)) {
+  /**
+   * @param {?string} current Current value of the query.
+   * @param {?string} previous Previous value of the query.
+   * @private
+   */
+  onQueryChanged_(current, previous) {
     if (previous !== undefined) {
       this.urlQuery_ = this.query_;
     }
   }
 
-  private onUrlQueryChanged_() {
+  /** @private */
+  onUrlQueryChanged_() {
     this.query_ = this.urlQuery_;
   }
 
-  private onStateChanged_() {
+  /** @private */
+  onStateChanged_() {
     this.debounceJob_ = Debouncer.debounce(
         this.debounceJob_, microTask, () => this.updateQueryParams_());
   }
 
-  private updateQueryParams_() {
+  /** @private */
+  updateQueryParams_() {
     if (this.searchTerm_) {
       this.queryParams_ = {q: this.searchTerm_};
     } else if (this.selectedId_ !== BOOKMARKS_BAR_ID) {
diff --git a/chrome/browser/resources/bookmarks/shared_style.ts b/chrome/browser/resources/bookmarks/shared_style.js
similarity index 100%
rename from chrome/browser/resources/bookmarks/shared_style.ts
rename to chrome/browser/resources/bookmarks/shared_style.js
diff --git a/chrome/browser/resources/bookmarks/shared_vars.ts b/chrome/browser/resources/bookmarks/shared_vars.js
similarity index 100%
rename from chrome/browser/resources/bookmarks/shared_vars.ts
rename to chrome/browser/resources/bookmarks/shared_vars.js
diff --git a/chrome/browser/resources/bookmarks/store.ts b/chrome/browser/resources/bookmarks/store.js
similarity index 74%
rename from chrome/browser/resources/bookmarks/store.ts
rename to chrome/browser/resources/bookmarks/store.js
index 3f23978..d13064d 100644
--- a/chrome/browser/resources/bookmarks/store.ts
+++ b/chrome/browser/resources/bookmarks/store.js
@@ -13,18 +13,22 @@
  * the store.
  */
 
-export class Store extends CrUiStore<BookmarksPageState> {
+/** @extends {CrUiStore<BookmarksPageState>} */
+export class Store extends CrUiStore {
   constructor() {
     super(createEmptyState(), reduceAction);
   }
 
-  static getInstance(): Store {
+  /** @return {!Store} */
+  static getInstance() {
     return instance || (instance = new Store());
   }
 
-  static setInstance(obj: Store) {
+  /** @param {Store} obj */
+  static setInstance(obj) {
     instance = obj;
   }
 }
 
-let instance: (Store|null) = null;
+/** @type {?Store} */
+let instance = null;
diff --git a/chrome/browser/resources/bookmarks/store_client.js b/chrome/browser/resources/bookmarks/store_client.js
new file mode 100644
index 0000000..cf0e3b3
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/store_client.js
@@ -0,0 +1,63 @@
+// Copyright 2017 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 {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClient as CrUiStoreClient, StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
+
+import {Store} from './store.js';
+import {BookmarksPageState} from './types.js';
+
+/**
+ * @fileoverview Defines StoreClient, a Polymer behavior to tie a front-end
+ * element to back-end data from the store.
+ */
+
+/**
+ * @polymerBehavior
+ */
+const BookmarksStoreClientImpl = {
+  /**
+   * @param {string} localProperty
+   * @param {function(Object)} valueGetter
+   */
+  watch(localProperty, valueGetter) {
+    this.watch_(localProperty, valueGetter);
+  },
+
+  /**
+   * @return {BookmarksPageState}
+   */
+  getState() {
+    return this.getStore().data;
+  },
+
+  /**
+   * @return {Store}
+   */
+  getStore() {
+    return Store.getInstance();
+  },
+};
+
+export class BookmarksStoreClientInterface {
+  /**
+   * @param {string} localProperty
+   * @param {function(Object)} valueGetter
+   */
+  watch(localProperty, valueGetter) {}
+
+  /** @return {BookmarksPageState} */
+  getState() {}
+
+  /** @return {Store} */
+  getStore() {}
+}
+
+/**
+ * @polymerBehavior
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ */
+export const StoreClient = [CrUiStoreClient, BookmarksStoreClientImpl];
diff --git a/chrome/browser/resources/bookmarks/store_client.ts b/chrome/browser/resources/bookmarks/store_client.ts
deleted file mode 100644
index b7ed7c09..0000000
--- a/chrome/browser/resources/bookmarks/store_client.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 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 {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
-import {StoreClient as CrUiStoreClient, StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {Store} from './store.js';
-import {BookmarksPageState} from './types.js';
-
-/**
- * @fileoverview Defines StoreClient, a Polymer behavior to tie a front-end
- * element to back-end data from the store.
- */
-
-const BookmarksStoreClientImpl = {
-  watch(localProperty: string, valueGetter: (p: BookmarksPageState) => any) {
-    (this as any).watch_(localProperty, valueGetter);
-  },
-
-  getState(): BookmarksPageState {
-    return this.getStore().data;
-  },
-
-  getStore(): Store {
-    return Store.getInstance();
-  },
-};
-
-export interface BookmarksStoreClientInterface extends
-    CrUiStoreClientInterface {
-  watch(localProperty: string,
-        valueGetter: (p: BookmarksPageState) => any): void;
-
-  getState(): BookmarksPageState;
-
-  getStore(): Store;
-}
-
-export const StoreClient = [CrUiStoreClient, BookmarksStoreClientImpl];
diff --git a/chrome/browser/resources/bookmarks/toolbar.ts b/chrome/browser/resources/bookmarks/toolbar.js
similarity index 71%
rename from chrome/browser/resources/bookmarks/toolbar.ts
rename to chrome/browser/resources/bookmarks/toolbar.js
index 86e6f729..0e5cdde 100644
--- a/chrome/browser/resources/bookmarks/toolbar.ts
+++ b/chrome/browser/resources/bookmarks/toolbar.js
@@ -7,13 +7,12 @@
 import 'chrome://resources/cr_elements/icons.m.js';
 import './shared_style.js';
 import './strings.m.js';
-import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
-import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js';
 
 import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
 import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js';
+import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -23,12 +22,16 @@
 import {BookmarksStoreClientInterface, StoreClient} from './store_client.js';
 import {BookmarksPageState} from './types.js';
 
-const BookmarksToolbarElementBase =
-    mixinBehaviors([StoreClient], PolymerElement) as {
-  new (): PolymerElement & BookmarksStoreClientInterface &
-      StoreObserver<BookmarksPageState>
-}
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {BookmarksStoreClientInterface}
+ * @implements {CrUiStoreClientInterface}
+ * @implements {StoreObserver<BookmarksPageState>}
+ */
+const BookmarksToolbarElementBase = mixinBehaviors(StoreClient, PolymerElement);
 
+/** @polymer */
 export class BookmarksToolbarElement extends BookmarksToolbarElementBase {
   static get is() {
     return 'bookmarks-toolbar';
@@ -51,49 +54,52 @@
         readOnly: true,
       },
 
+      /** @private */
       narrow_: {
         type: Boolean,
         reflectToAttribute: true,
       },
 
+      /** @private */
       searchTerm_: {
         type: String,
         observer: 'onSearchTermChanged_',
       },
 
+      /** @private {!Set<string>} */
       selectedItems_: Object,
 
+      /** @private */
       globalCanEdit_: Boolean,
     };
   }
 
-  sidebarWidth: string;
-  showSelectionOverlay: boolean;
-  private narrow_: boolean;
-  private searchTerm_: string;
-  private selectedItems_: Set<string>;
-  private globalCanEdit_: boolean;
-
   connectedCallback() {
     super.connectedCallback();
-    this.watch('searchTerm_', function(state: BookmarksPageState) {
+    this.watch('searchTerm_', function(state) {
       return state.search.term;
     });
-    this.watch('selectedItems_', function(state: BookmarksPageState) {
+    this.watch('selectedItems_', function(state) {
       return state.selection.items;
     });
-    this.watch('globalCanEdit_', function(state: BookmarksPageState) {
+    this.watch('globalCanEdit_', function(state) {
       return state.prefs.canEdit;
     });
     this.updateFromStore();
   }
 
-  get searchField(): CrToolbarSearchFieldElement {
-    return this.shadowRoot!.querySelector<CrToolbarElement>('cr-toolbar')!
+  /** @return {CrToolbarSearchFieldElement} */
+  get searchField() {
+    return /** @type {CrToolbarElement} */ (
+               this.shadowRoot.querySelector('cr-toolbar'))
         .getSearchField();
   }
 
-  private onMenuButtonOpenTap_(e: Event) {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onMenuButtonOpenTap_(e) {
     this.dispatchEvent(new CustomEvent('open-command-menu', {
       bubbles: true,
       composed: true,
@@ -104,45 +110,65 @@
     }));
   }
 
-  private onDeleteSelectionTap_() {
+  /** @private */
+  onDeleteSelectionTap_() {
     const selection = this.selectedItems_;
     const commandManager = BookmarksCommandManagerElement.getInstance();
     assert(commandManager.canExecute(Command.DELETE, selection));
     commandManager.handle(Command.DELETE, selection);
   }
 
-  private onClearSelectionTap_() {
+  /** @private */
+  onClearSelectionTap_() {
     const commandManager = BookmarksCommandManagerElement.getInstance();
     assert(
         commandManager.canExecute(Command.DESELECT_ALL, this.selectedItems_));
     commandManager.handle(Command.DESELECT_ALL, this.selectedItems_);
   }
 
-  private onSearchChanged_(e: CustomEvent<string>) {
+  /**
+   * @param {!CustomEvent<string>} e
+   * @private
+   */
+  onSearchChanged_(e) {
     if (e.detail !== this.searchTerm_) {
       this.dispatch(setSearchTerm(e.detail));
     }
   }
 
-  private onSidebarWidthChanged_() {
+  /** @private */
+  onSidebarWidthChanged_() {
     this.style.setProperty('--sidebar-width', this.sidebarWidth);
   }
 
-  private onSearchTermChanged_() {
+  /** @private */
+  onSearchTermChanged_() {
     this.searchField.setValue(this.searchTerm_ || '');
   }
 
-  private shouldShowSelectionOverlay_(): boolean {
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowSelectionOverlay_() {
     return this.selectedItems_.size > 1 && this.globalCanEdit_;
   }
 
-  private canDeleteSelection_(): boolean {
+  /**
+   * @return {boolean}
+   * @private
+   */
+  canDeleteSelection_() {
     return this.showSelectionOverlay &&
         BookmarksCommandManagerElement.getInstance().canExecute(
             Command.DELETE, this.selectedItems_);
   }
 
-  private getItemsSelectedString_(): string {
+  /**
+   * @return {string}
+   * @private
+   */
+  getItemsSelectedString_() {
     return loadTimeData.getStringF('itemsSelected', this.selectedItems_.size);
   }
 }
diff --git a/chrome/browser/resources/bookmarks/tsconfig_base.json b/chrome/browser/resources/bookmarks/tsconfig_base.json
deleted file mode 100644
index 3d55197..0000000
--- a/chrome/browser/resources/bookmarks/tsconfig_base.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "extends": "../../../../tools/typescript/tsconfig_base.json",
-  "compilerOptions": {
-    "noPropertyAccessFromIndexSignature": false,
-    "noUnusedLocals": false,
-    "noUnusedParameters": false,
-    "strictPropertyInitialization": false
-  }
-}
diff --git a/chrome/browser/resources/bookmarks/types.js b/chrome/browser/resources/bookmarks/types.js
new file mode 100644
index 0000000..0031ae7c
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/types.js
@@ -0,0 +1,106 @@
+// Copyright 2017 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 {DropPosition, IncognitoAvailability} from './constants.js';
+
+/**
+ * @fileoverview Closure typedefs for Bookmarks.
+ */
+
+/**
+ * A normalized version of chrome.bookmarks.BookmarkTreeNode.
+ * @typedef {{
+ *   id: string,
+ *   parentId: (string|undefined),
+ *   url: (string|undefined),
+ *   title: string,
+ *   dateAdded: (number|undefined),
+ *   dateGroupModified: (number|undefined),
+ *   unmodifiable: (string|undefined),
+ *   children: (!Array<string>|undefined),
+ * }}
+ */
+export let BookmarkNode;
+
+/**
+ * @typedef {!Object<string, BookmarkNode>}
+ */
+export let NodeMap;
+
+/**
+ * @typedef {{
+ *   items: !Set<string>,
+ *   anchor: ?string,
+ * }}
+ *
+ * |items| is used as a set and all values in the map are true.
+ */
+export let SelectionState;
+
+/**
+ * Note:
+ * - If |results| is null, it means no search results have been returned. This
+ *   is different to |results| being [], which means the last search returned 0
+ *   results.
+ * - |term| is the last search that was performed by the user, and |results| are
+ *   the last results that were returned from the backend. We don't clear
+ *   |results| on incremental searches, meaning that |results| can be 'stale'
+ *   data from a previous search term (while |inProgress| is true). If you need
+ *   to know the exact search term used to generate |results|, you'll need to
+ *   add a new field to the state to track it (eg, SearchState.resultsTerm).
+ * @typedef {{
+ *   term: string,
+ *   inProgress: boolean,
+ *   results: ?Array<string>,
+ * }}
+ */
+export let SearchState;
+
+/** @typedef {!Map<string, boolean>} */
+export let FolderOpenState;
+
+/**
+ * @typedef {{
+ *   canEdit: boolean,
+ *   incognitoAvailability: IncognitoAvailability,
+ * }}
+ */
+export let PreferencesState;
+
+/**
+ * @typedef {{
+ *   nodes: NodeMap,
+ *   selectedFolder: string,
+ *   folderOpenState: FolderOpenState,
+ *   prefs: PreferencesState,
+ *   search: SearchState,
+ *   selection: SelectionState,
+ * }}
+ */
+export let BookmarksPageState;
+
+/** @typedef {{element: BookmarkElement, position: DropPosition}} */
+export let DropDestination;
+
+export class BookmarkElement extends HTMLElement {
+  constructor() {
+    super();
+
+    /** @type {string} */
+    this.itemId = '';
+  }
+
+  /** @return {HTMLElement} */
+  getDropTarget() {}
+}
+
+export class DragData {
+  constructor() {
+    /** @type {Array<chrome.bookmarks.BookmarkTreeNode>} */
+    this.elements = null;
+
+    /** @type {boolean} */
+    this.sameProfile = false;
+  }
+}
diff --git a/chrome/browser/resources/bookmarks/types.ts b/chrome/browser/resources/bookmarks/types.ts
deleted file mode 100644
index d5f451d..0000000
--- a/chrome/browser/resources/bookmarks/types.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2017 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 {DropPosition, IncognitoAvailability, MenuSource} from './constants.js';
-
-/**
- * @fileoverview Closure typedefs for Bookmarks.
- */
-
-// A normalized version of chrome.bookmarks.BookmarkTreeNode.
-export type BookmarkNode = {
-  id: string,
-  parentId?: string,
-  url?: string,
-  title: string,
-  dateAdded?: number,
-  dateGroupModified?: number,
-  unmodifiable?: string,
-  children?: string[],
-};
-
-export interface ObjectMap<Type> {
-  [index: string]: Type;
-}
-
-export type NodeMap = ObjectMap<BookmarkNode>;
-
-// |items| is used as a set and all values in the map are true.
-export type SelectionState = {
-  items: Set<string>,
-  anchor?: string|null,
-};
-
-export type OpenCommandMenuDetail = {
-  x?: number,
-  y?: number,
-  source: MenuSource,
-  targetId?: string,
-  targetElement?: HTMLElement,
-};
-
-/**
- * Note:
- * - If |results| is null, it means no search results have been returned. This
- *   is different to |results| being [], which means the last search returned 0
- *   results.
- * - |term| is the last search that was performed by the user, and |results| are
- *   the last results that were returned from the backend. We don't clear
- *   |results| on incremental searches, meaning that |results| can be 'stale'
- *   data from a previous search term (while |inProgress| is true). If you need
- *   to know the exact search term used to generate |results|, you'll need to
- *   add a new field to the state to track it (eg, SearchState.resultsTerm).
- */
-export type SearchState = {
-  term: string,
-  inProgress: boolean,
-  results: string[]|null,
-};
-
-export type FolderOpenState = Map<string, boolean>;
-
-export type PreferencesState = {
-  canEdit: boolean, incognitoAvailability: IncognitoAvailability;
-};
-
-export type BookmarksPageState = {
-  nodes: NodeMap,
-  selectedFolder: string,
-  folderOpenState: FolderOpenState,
-  prefs: PreferencesState,
-  search: SearchState,
-  selection: SelectionState,
-};
-
-export type DropDestination = {
-  element: BookmarkElement,
-  position: DropPosition,
-};
-
-export class BookmarkElement extends HTMLElement {
-  itemId: string = '';
-
-  getDropTarget(): HTMLElement|null {
-    return null;
-  }
-}
-
-export class DragData {
-  elements: chrome.bookmarks.BookmarkTreeNode[]|null = null;
-  sameProfile: boolean = false;
-}
diff --git a/chrome/browser/resources/bookmarks/util.js b/chrome/browser/resources/bookmarks/util.js
new file mode 100644
index 0000000..b0e1184
--- /dev/null
+++ b/chrome/browser/resources/bookmarks/util.js
@@ -0,0 +1,218 @@
+// Copyright 2017 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 {assert} from 'chrome://resources/js/assert.m.js';
+
+import {BOOKMARKS_BAR_ID, IncognitoAvailability, ROOT_NODE_ID} from './constants.js';
+import {BookmarkNode, BookmarksPageState, NodeMap} from './types.js';
+
+/**
+ * @fileoverview Utility functions for the Bookmarks page.
+ */
+
+/**
+ * Returns the list of bookmark IDs to be displayed in the UI, taking into
+ * account search and the currently selected folder.
+ * @param {!BookmarksPageState} state
+ * @return {!Array<string>}
+ */
+export function getDisplayedList(state) {
+  if (isShowingSearch(state)) {
+    return assert(state.search.results);
+  }
+
+  return assert(state.nodes[state.selectedFolder].children);
+}
+
+/**
+ * @param {chrome.bookmarks.BookmarkTreeNode} treeNode
+ * @return {!BookmarkNode}
+ */
+export function normalizeNode(treeNode) {
+  const node = Object.assign({}, treeNode);
+  // Node index is not necessary and not kept up-to-date. Remove it from the
+  // data structure so we don't accidentally depend on the incorrect
+  // information.
+  delete node.index;
+
+  if (!('url' in node)) {
+    // The onCreated API listener returns folders without |children| defined.
+    node.children = (node.children || []).map(function(child) {
+      return child.id;
+    });
+  }
+  return /** @type {BookmarkNode} */ (node);
+}
+
+/**
+ * @param {chrome.bookmarks.BookmarkTreeNode} rootNode
+ * @return {NodeMap}
+ */
+export function normalizeNodes(rootNode) {
+  /** @type {NodeMap} */
+  const nodeMap = {};
+  const stack = [];
+  stack.push(rootNode);
+
+  while (stack.length > 0) {
+    const node = stack.pop();
+    nodeMap[node.id] = normalizeNode(node);
+    if (!node.children) {
+      continue;
+    }
+
+    node.children.forEach(function(child) {
+      stack.push(child);
+    });
+  }
+
+  return nodeMap;
+}
+
+/** @return {!BookmarksPageState} */
+export function createEmptyState() {
+  return {
+    nodes: {},
+    selectedFolder: BOOKMARKS_BAR_ID,
+    folderOpenState: new Map(),
+    prefs: {
+      canEdit: true,
+      incognitoAvailability: IncognitoAvailability.ENABLED,
+    },
+    search: {
+      term: '',
+      inProgress: false,
+      results: null,
+    },
+    selection: {
+      items: new Set(),
+      anchor: null,
+    },
+  };
+}
+
+/**
+ * @param {BookmarksPageState} state
+ * @return {boolean}
+ */
+export function isShowingSearch(state) {
+  return state.search.results != null;
+}
+
+/**
+ * Returns true if the node with ID |itemId| is modifiable, allowing
+ * the node to be renamed, moved or deleted. Note that if a node is
+ * uneditable, it may still have editable children (for example, the top-level
+ * folders).
+ * @param {BookmarksPageState} state
+ * @param {string} itemId
+ * @return {boolean}
+ */
+export function canEditNode(state, itemId) {
+  return itemId !== ROOT_NODE_ID &&
+      state.nodes[itemId].parentId !== ROOT_NODE_ID &&
+      !state.nodes[itemId].unmodifiable && state.prefs.canEdit;
+}
+
+/**
+ * Returns true if it is possible to modify the children list of the node with
+ * ID |itemId|. This includes rearranging the children or adding new ones.
+ * @param {BookmarksPageState} state
+ * @param {string} itemId
+ * @return {boolean}
+ */
+export function canReorderChildren(state, itemId) {
+  return itemId !== ROOT_NODE_ID && !state.nodes[itemId].unmodifiable &&
+      state.prefs.canEdit;
+}
+
+/**
+ * @param {string} id
+ * @param {NodeMap} nodes
+ * @return {boolean}
+ */
+export function hasChildFolders(id, nodes) {
+  const children = nodes[id].children;
+  for (let i = 0; i < children.length; i++) {
+    if (nodes[children[i]].children) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Get all descendants of a node, including the node itself.
+ * @param {NodeMap} nodes
+ * @param {string} baseId
+ * @return {!Set<string>}
+ */
+export function getDescendants(nodes, baseId) {
+  const descendants = new Set();
+  const stack = [];
+  stack.push(baseId);
+
+  while (stack.length > 0) {
+    const id = stack.pop();
+    const node = nodes[id];
+
+    if (!node) {
+      continue;
+    }
+
+    descendants.add(id);
+
+    if (!node.children) {
+      continue;
+    }
+
+    node.children.forEach(function(childId) {
+      stack.push(childId);
+    });
+  }
+
+  return descendants;
+}
+
+/**
+ * @param {!Object<string, T>} map
+ * @param {!Set<string>} ids
+ * @return {!Object<string, T>}
+ * @template T
+ */
+export function removeIdsFromObject(map, ids) {
+  const newObject = Object.assign({}, map);
+  ids.forEach(function(id) {
+    delete newObject[id];
+  });
+  return newObject;
+}
+
+
+/**
+ * @param {!Map<string, T>} map
+ * @param {!Set<string>} ids
+ * @return {!Map<string, T>}
+ * @template T
+ */
+export function removeIdsFromMap(map, ids) {
+  const newMap = new Map(map);
+  ids.forEach(function(id) {
+    newMap.delete(id);
+  });
+  return newMap;
+}
+
+/**
+ * @param {!Set<string>} set
+ * @param {!Set<string>} ids
+ * @return {!Set<string>}
+ */
+export function removeIdsFromSet(set, ids) {
+  const difference = new Set(set);
+  ids.forEach(function(id) {
+    difference.delete(id);
+  });
+  return difference;
+}
diff --git a/chrome/browser/resources/bookmarks/util.ts b/chrome/browser/resources/bookmarks/util.ts
deleted file mode 100644
index 26be15c..0000000
--- a/chrome/browser/resources/bookmarks/util.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2017 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 {assert} from 'chrome://resources/js/assert.m.js';
-
-import {BOOKMARKS_BAR_ID, IncognitoAvailability, ROOT_NODE_ID} from './constants.js';
-import {BookmarkNode, BookmarksPageState, NodeMap, ObjectMap} from './types.js';
-
-/**
- * @fileoverview Utility functions for the Bookmarks page.
- */
-
-export function getDisplayedList(state: BookmarksPageState): string[] {
-  if (isShowingSearch(state)) {
-    return assert(state.search.results!);
-  }
-
-  return assert(state.nodes[state.selectedFolder]!.children!);
-}
-
-export function normalizeNode(treeNode: chrome.bookmarks.BookmarkTreeNode):
-    BookmarkNode {
-  const node = Object.assign({}, treeNode);
-  // Node index is not necessary and not kept up-to-date. Remove it from the
-  // data structure so we don't accidentally depend on the incorrect
-  // information.
-  delete node.index;
-  delete node.children;
-  const bookmarkNode = node as unknown as BookmarkNode;
-
-  if (!('url' in node)) {
-    // The onCreated API listener returns folders without |children| defined.
-    bookmarkNode.children = (treeNode.children || []).map(function(child) {
-      return child.id;
-    });
-  }
-  return bookmarkNode;
-}
-
-export function normalizeNodes(rootNode: chrome.bookmarks.BookmarkTreeNode):
-    NodeMap {
-  const nodeMap: NodeMap = {};
-  const stack = [];
-  stack.push(rootNode);
-
-  while (stack.length > 0) {
-    const node = stack.pop()!;
-    nodeMap[node.id] = normalizeNode(node);
-    if (!node.children) {
-      continue;
-    }
-
-    node.children.forEach(function(child) {
-      stack.push(child);
-    });
-  }
-
-  return nodeMap;
-}
-
-export function createEmptyState(): BookmarksPageState {
-  return {
-    nodes: {},
-    selectedFolder: BOOKMARKS_BAR_ID,
-    folderOpenState: new Map(),
-    prefs: {
-      canEdit: true,
-      incognitoAvailability: IncognitoAvailability.ENABLED,
-    },
-    search: {
-      term: '',
-      inProgress: false,
-      results: null,
-    },
-    selection: {
-      items: new Set(),
-      anchor: null,
-    },
-  };
-}
-
-export function isShowingSearch(state: BookmarksPageState): boolean {
-  return state.search.results != null;
-}
-
-/**
- * Returns true if the node with ID |itemId| is modifiable, allowing
- * the node to be renamed, moved or deleted. Note that if a node is
- * uneditable, it may still have editable children (for example, the top-level
- * folders).
- */
-export function canEditNode(
-    state: BookmarksPageState, itemId: string): boolean {
-  return itemId !== ROOT_NODE_ID &&
-      state.nodes![itemId]!.parentId !== ROOT_NODE_ID &&
-      !state.nodes![itemId]!.unmodifiable && state.prefs.canEdit;
-}
-
-/**
- * Returns true if it is possible to modify the children list of the node with
- * ID |itemId|. This includes rearranging the children or adding new ones.
- */
-export function canReorderChildren(
-    state: BookmarksPageState, itemId: string): boolean {
-  return itemId !== ROOT_NODE_ID && !state.nodes[itemId]!.unmodifiable &&
-      state.prefs.canEdit;
-}
-
-export function hasChildFolders(id: string, nodes: NodeMap): boolean {
-  const children = nodes[id]!.children!;
-  for (let i = 0; i < children.length; i++) {
-    if (nodes[children[i]!]!.children) {
-      return true;
-    }
-  }
-  return false;
-}
-
-export function getDescendants(nodes: NodeMap, baseId: string): Set<string> {
-  const descendants = new Set() as Set<string>;
-  const stack: string[] = [];
-  stack.push(baseId);
-
-  while (stack.length > 0) {
-    const id = stack.pop()!;
-    const node = nodes[id];
-
-    if (!node) {
-      continue;
-    }
-
-    descendants.add(id);
-
-    if (!node!.children) {
-      continue;
-    }
-
-    node!.children.forEach(function(childId) {
-      stack.push(childId);
-    });
-  }
-
-  return descendants;
-}
-
-export function removeIdsFromObject<Type>(
-    map: ObjectMap<Type>, ids: Set<string>): ObjectMap<Type> {
-  const newObject = Object.assign({}, map);
-  ids.forEach(function(id) {
-    delete newObject[id];
-  });
-  return newObject;
-}
-
-
-export function removeIdsFromMap<Type>(
-    map: Map<string, Type>, ids: Set<string>): Map<string, Type> {
-  const newMap = new Map(map);
-  ids.forEach(function(id) {
-    newMap.delete(id);
-  });
-  return newMap;
-}
-
-export function removeIdsFromSet(
-    set: Set<string>, ids: Set<string>): Set<string> {
-  const difference = new Set(set);
-  ids.forEach(function(id) {
-    difference.delete(id);
-  });
-  return difference;
-}
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
index 4db7224..a2fbb0d 100644
--- a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
@@ -500,8 +500,7 @@
    */
   newMinPinLengthChanged_() {
     PluralStringProxyImpl.getInstance()
-        .getPluralString('securityKeysNewPIN',
-                         /** @type {number} */ (this.newMinPinLength_))
+        .getPluralString('securityKeysNewPIN', this.newMinPinLength_)
         .then(string => this.newPINDialogDescription_ = string);
   },
 
diff --git a/chrome/browser/resources/welcome/BUILD.gn b/chrome/browser/resources/welcome/BUILD.gn
index 6b365d4..7a04bed 100644
--- a/chrome/browser/resources/welcome/BUILD.gn
+++ b/chrome/browser/resources/welcome/BUILD.gn
@@ -176,7 +176,6 @@
   ]
   definitions = [
     "//tools/typescript/definitions/bookmarks.d.ts",
-    "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/chrome_send.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
   ]
diff --git a/chrome/browser/safe_browsing/generated_safe_browsing_pref.h b/chrome/browser/safe_browsing/generated_safe_browsing_pref.h
index 2b3c931..55cb7af3 100644
--- a/chrome/browser/safe_browsing/generated_safe_browsing_pref.h
+++ b/chrome/browser/safe_browsing/generated_safe_browsing_pref.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SAFE_BROWSING_GENERATED_SAFE_BROWSING_PREF_H_
 #define CHROME_BROWSER_SAFE_BROWSING_GENERATED_SAFE_BROWSING_PREF_H_
 
-#include "base/scoped_observer.h"
 #include "chrome/browser/extensions/api/settings_private/generated_pref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/prefs/pref_change_registrar.h"
diff --git a/chrome/browser/share/BUILD.gn b/chrome/browser/share/BUILD.gn
index f203366..46c68f3d 100644
--- a/chrome/browser/share/BUILD.gn
+++ b/chrome/browser/share/BUILD.gn
@@ -17,6 +17,7 @@
     "share_history.h",
   ]
   deps = [
+    ":jni_headers",
     "//base",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/share/android:jni_headers",
@@ -38,13 +39,24 @@
   sources = [
     "android/java/src/org/chromium/chrome/browser/share/ChromeShareExtras.java",
     "android/java/src/org/chromium/chrome/browser/share/ShareDelegate.java",
+    "android/java/src/org/chromium/chrome/browser/share/ShareHistoryBridge.java",
     "android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeOptionShareCallback.java",
   ]
 
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+
   deps = [
+    ":jni_headers",
+    "//base:base_java",
+    "//chrome/browser/preferences:java",
+    "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
     "//components/browser_ui/share/android:java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//url:gurl_java",
   ]
 }
+
+generate_jni("jni_headers") {
+  sources = [ "android/java/src/org/chromium/chrome/browser/share/ShareHistoryBridge.java" ]
+}
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareHistoryBridge.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareHistoryBridge.java
new file mode 100644
index 0000000..2489f8cd
--- /dev/null
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareHistoryBridge.java
@@ -0,0 +1,24 @@
+// Copyright 2021 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.
+
+package org.chromium.chrome.browser.share;
+
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.chrome.browser.profiles.Profile;
+
+/**
+ * This class is a shim that wraps the JNI interface to the C++-side
+ * ShareHistory object.
+ */
+public class ShareHistoryBridge {
+    public static void addShareEntry(Profile profile, String target) {
+        assert profile != null;
+        ShareHistoryBridgeJni.get().addShareEntry(profile, target);
+    }
+
+    @NativeMethods
+    public interface Natives {
+        void addShareEntry(Profile profile, String string);
+    }
+}
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
index 6a2ae7ac..bab7910 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ChromeShareExtras;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator;
@@ -273,7 +274,11 @@
                                 mLinkGenerationStatusForMetrics);
                     }
                     mBottomSheetController.hideContent(mBottomSheet, true);
-                    ShareHelper.showDefaultShareUi(params, saveLastUsed);
+                    Profile profile = null;
+                    if (mTabProvider.get() != null && mTabProvider.get().getWebContents() != null) {
+                        profile = Profile.fromWebContents(mTabProvider.get().getWebContents());
+                    }
+                    ShareHelper.showDefaultShareUi(params, profile, saveLastUsed);
                 },
                 /*displayNew*/ false);
         models.add(morePropertyModel);
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java
index 416211ae..a748fef5 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java
@@ -18,6 +18,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ChromeShareExtras;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator.LinkGeneration;
@@ -89,12 +90,14 @@
 
     private final BottomSheetController mBottomSheetController;
     private final PackageManager mPackageManager;
+    private final Profile mProfile;
 
     // TODO(crbug/1022172): Should be package-protected once modularization is complete.
-    public ShareSheetPropertyModelBuilder(
-            BottomSheetController bottomSheetController, PackageManager packageManager) {
+    public ShareSheetPropertyModelBuilder(BottomSheetController bottomSheetController,
+            PackageManager packageManager, Profile profile) {
         mBottomSheetController = bottomSheetController;
         mPackageManager = packageManager;
+        mProfile = profile;
     }
 
     /**
@@ -214,7 +217,7 @@
             callback.onTargetChosen(component);
         }
         if (saveLastUsed) {
-            ShareHelper.setLastShareComponentName(component);
+            ShareHelper.setLastShareComponentName(mProfile, component);
         }
         mBottomSheetController.hideContent(bottomSheet, true);
         // Fire intent through ShareHelper.
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
index d77f6a81..8e74c66 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
@@ -33,6 +33,7 @@
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ChromeShareExtras;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator.LinkGeneration;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType;
@@ -65,6 +66,8 @@
     @Mock
     private PackageManager mPackageManager;
     @Mock
+    private Profile mProfile;
+    @Mock
     private ShareParams mParams;
     @Mock
     private ResolveInfo mTextResolveInfo1;
@@ -93,7 +96,7 @@
         MockitoAnnotations.initMocks(this);
         mActivityTestRule.launchActivity(null);
         mActivity = mActivityTestRule.getActivity();
-        mPropertyModelBuilder = new ShareSheetPropertyModelBuilder(null, mPackageManager);
+        mPropertyModelBuilder = new ShareSheetPropertyModelBuilder(null, mPackageManager, mProfile);
 
         setUpResolveInfo(mTextResolveInfo1, "textPackage1", sTextModelLabel1);
         setUpResolveInfo(mTextResolveInfo2, "textPackage2", sTextModelLabel2);
diff --git a/chrome/browser/share/share_history.cc b/chrome/browser/share/share_history.cc
index ad80456..bc839ad96 100644
--- a/chrome/browser/share/share_history.cc
+++ b/chrome/browser/share/share_history.cc
@@ -4,15 +4,21 @@
 
 #include "chrome/browser/share/share_history.h"
 
+#include "base/android/jni_string.h"
 #include "base/containers/flat_map.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/share/proto/share_history_message.pb.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "content/public/browser/storage_partition.h"
 
+#include "chrome/browser/share/jni_headers/ShareHistoryBridge_jni.h"
+
+using base::android::JavaParamRef;
+
 namespace sharing {
 
 namespace {
@@ -43,15 +49,22 @@
 
 // static
 void ShareHistory::CreateForProfile(Profile* profile) {
+  CHECK(!profile->IsOffTheRecord());
   auto instance = std::make_unique<ShareHistory>(profile);
   profile->SetUserData(kShareHistoryKey, base::WrapUnique(instance.release()));
 }
 
 // static
 ShareHistory* ShareHistory::Get(Profile* profile) {
+  if (profile->IsOffTheRecord())
+    return nullptr;
+
   base::SupportsUserData::Data* instance =
       profile->GetUserData(kShareHistoryKey);
-  DCHECK(instance);
+  if (!instance) {
+    CreateForProfile(profile);
+    instance = profile->GetUserData(kShareHistoryKey);
+  }
   return static_cast<ShareHistory*>(instance);
 }
 
@@ -194,3 +207,12 @@
 }
 
 }  // namespace sharing
+
+void JNI_ShareHistoryBridge_AddShareEntry(JNIEnv* env,
+                                          const JavaParamRef<jobject>& jprofile,
+                                          const JavaParamRef<jstring>& name) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  auto* instance = sharing::ShareHistory::Get(profile);
+  if (instance)
+    instance->AddShareEntry(base::android::ConvertJavaStringToUTF8(env, name));
+}
diff --git a/chrome/browser/share/share_history_unittest.cc b/chrome/browser/share/share_history_unittest.cc
index f53b9a3..7b1c7fef 100644
--- a/chrome/browser/share/share_history_unittest.cc
+++ b/chrome/browser/share/share_history_unittest.cc
@@ -110,6 +110,7 @@
     return result;
   }
 
+  TestingProfile* profile() { return &profile_; }
   ShareHistory* db() { return db_.get(); }
 
   leveldb_proto::test::FakeDB<mojom::ShareHistory>* backing_db() {
@@ -198,4 +199,11 @@
   EXPECT_EQ(result.size(), 0U);
 }
 
+TEST_F(ShareHistoryTest, OffTheRecordProfileHasNoInstance) {
+  Profile* otr_profile = profile()->GetOffTheRecordProfile(
+      Profile::OTRProfileID::CreateUniqueForTesting(), true);
+  ShareHistory* db = ShareHistory::Get(otr_profile);
+  ASSERT_FALSE(db);
+}
+
 }  // namespace sharing
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index b3b6bca..36ead96 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/notreached.h"
-#include "base/scoped_observer.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.h b/chrome/browser/supervised_user/child_accounts/child_account_service.h
index 595e77d..0f3e1ef 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service.h
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service.h
@@ -12,7 +12,6 @@
 #include "base/callback_list.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/supervised_user/child_accounts/family_info_fetcher.h"
diff --git a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
index fc2b5a1..4182d53 100644
--- a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
+++ b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/format_macros.h"
-#include "base/scoped_observer.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
 #include "components/sync/driver/profile_sync_service.h"
diff --git a/chrome/browser/sync/trusted_vault_client_android.cc b/chrome/browser/sync/trusted_vault_client_android.cc
index 8d518d3..3e3f62a2 100644
--- a/chrome/browser/sync/trusted_vault_client_android.cc
+++ b/chrome/browser/sync/trusted_vault_client_android.cc
@@ -139,6 +139,10 @@
   NOTREACHED();
 }
 
+void TrustedVaultClientAndroid::RemoveAllStoredKeys() {
+  // StoreKeys() not supported on Android, nothing to remove.
+}
+
 void TrustedVaultClientAndroid::MarkKeysAsStale(
     const CoreAccountInfo& account_info,
     base::OnceCallback<void(bool)> cb) {
diff --git a/chrome/browser/sync/trusted_vault_client_android.h b/chrome/browser/sync/trusted_vault_client_android.h
index 1d5fe62..e2158d0 100644
--- a/chrome/browser/sync/trusted_vault_client_android.h
+++ b/chrome/browser/sync/trusted_vault_client_android.h
@@ -65,6 +65,7 @@
   void StoreKeys(const std::string& gaia_id,
                  const std::vector<std::vector<uint8_t>>& keys,
                  int last_key_version) override;
+  void RemoveAllStoredKeys() override;
   void MarkKeysAsStale(const CoreAccountInfo& account_info,
                        base::OnceCallback<void(bool)> cb) override;
   void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index b0ff63b..fddf235 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -5,7 +5,6 @@
 #include <memory>
 
 #include "base/bind.h"
-#include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
diff --git a/chrome/browser/translate/translate_test_utils.h b/chrome/browser/translate/translate_test_utils.h
index d2b6e8d..ea0cc92 100644
--- a/chrome/browser/translate/translate_test_utils.h
+++ b/chrome/browser/translate/translate_test_utils.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "components/translate/content/browser/content_translate_driver.h"
 #include "components/translate/content/browser/translate_waiter.h"
 #include "components/translate/core/common/translate_errors.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 917fae4..e6a92900 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -400,6 +400,7 @@
     "//chrome/services/qrcode_generator/public/mojom",
     "//components/about_ui",
     "//components/account_id",
+    "//components/accuracy_tips",
     "//components/autofill/content/browser:risk_proto",
     "//components/autofill/core/browser",
     "//components/autofill_assistant/browser/public:public",
@@ -2679,8 +2680,6 @@
       "//ash/components/os_feedback_ui",
       "//ash/components/pcie_peripheral",
       "//ash/constants",
-      "//ash/content/help_app_ui",
-      "//ash/content/help_app_ui/search:mojo_bindings",
       "//ash/content/scanning",
       "//ash/content/shimless_rma",
       "//ash/content/shortcut_customization_ui",
@@ -2732,6 +2731,8 @@
       "//chromeos/components/drivefs",
       "//chromeos/components/drivefs/mojom:mojom",
       "//chromeos/components/eche_app_ui",
+      "//chromeos/components/help_app_ui",
+      "//chromeos/components/help_app_ui/search:mojo_bindings",
       "//chromeos/components/local_search_service/public/cpp",
       "//chromeos/components/local_search_service/public/mojom",
       "//chromeos/components/media_app_ui",
diff --git a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java
index bd9a9ac6b..20735887 100644
--- a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java
+++ b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java
@@ -60,6 +60,13 @@
     boolean isLayoutVisible(@LayoutType int layoutType);
 
     /**
+     * Get the type of the layout that is currently active.
+     * @return The {@link LayoutType} of the active layout.
+     */
+    @LayoutType
+    int getActiveLayoutType();
+
+    /**
      * @param listener Registers {@code listener} for all layout status changes.
      */
     void addObserver(LayoutStateObserver listener);
diff --git a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java
index 212219b8..fe26a24f 100644
--- a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java
+++ b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java
@@ -13,10 +13,11 @@
  * The type info of the Layout. These types are bit flags, so they can be or-ed together to test for
  * multiple.
  */
-@IntDef({LayoutType.BROWSING, LayoutType.TAB_SWITCHER, LayoutType.TOOLBAR_SWIPE,
+@IntDef({LayoutType.NONE, LayoutType.BROWSING, LayoutType.TAB_SWITCHER, LayoutType.TOOLBAR_SWIPE,
         LayoutType.SIMPLE_ANIMATION})
 @Retention(RetentionPolicy.SOURCE)
 public @interface LayoutType {
+    int NONE = 0;
     int BROWSING = 1;
     int TAB_SWITCHER = 2;
     int TOOLBAR_SWIPE = 4;
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
index 1b657e2..4ad068a 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
@@ -686,6 +686,7 @@
 <translation id="545042621069398927">আপনার ডাউনলোডের স্পিড বাড়ানো হচ্ছে।</translation>
 <translation id="5454166040603940656"><ph name="PROVIDER" /> সহ</translation>
 <translation id="5456381639095306749">পৃষ্ঠা ডাউনলোড করুন</translation>
+<translation id="5458366071038729214">যেসব সাইট ফলো করছেন সেগুলো এখানে দেখতে পাবেন</translation>
 <translation id="548278423535722844">ম্যাপ অ্যাপ্লিকেশানে খুলুন</translation>
 <translation id="5483197086164197190">Chrome-এ নেভিগেট করুন</translation>
 <translation id="5487521232677179737">ডেটা সাফ করুন</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb
index af6c15d..0612a37 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb
@@ -461,7 +461,7 @@
 <translation id="3976396876660209797">Бул кыска жолду алып салып, кайра түзүү</translation>
 <translation id="3985215325736559418"><ph name="FILE_NAME" /> файлын кайра жүктөп аласызбы?</translation>
 <translation id="3987993985790029246">Шилтм көчр</translation>
-<translation id="3988213473815854515">Жайгашкан жер дайындарына уруксат берилген</translation>
+<translation id="3988213473815854515">Жайгашкан жерди аныктоого уруксат берилген</translation>
 <translation id="3988466920954086464">Ыкчам издөө жыйынтыктарын ушул панелде көрүү</translation>
 <translation id="4000212216660919741">Үйдө оффлайн режиминде</translation>
 <translation id="4016425174436051808">Жазылган жок. Бир жерден ката кетти.</translation>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java
index 2d199ee..f4ec1fe 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java
@@ -85,6 +85,9 @@
         mModel = model;
         mIsVisibilityManuallyControlled = manualVisibilityControl;
 
+        mIsOnValidLayout = (mLayoutStateProvider.getActiveLayoutType() & layoutsToShowOn) > 0;
+        updateVisibility();
+
         mSceneChangeObserver = new LayoutStateObserver() {
             @Override
             public void onStartedShowing(@LayoutType int layout, boolean showToolbar) {
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.cc b/chrome/browser/ui/app_list/app_list_client_impl.cc
index 1c7ca499..a7afa1d 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl.cc
@@ -78,7 +78,21 @@
 AppListClientImpl::~AppListClientImpl() {
   SetProfile(nullptr);
 
-  user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
+  auto* user_manager = user_manager::UserManager::Get();
+  user_manager->RemoveSessionStateObserver(this);
+
+  // We assume that the current user is new if `state_for_new_user_` has value.
+  if (state_for_new_user_.has_value() &&
+      !state_for_new_user_->showing_recorded) {
+    DCHECK(user_manager->IsCurrentUserNew());
+
+    // Prefer the function to the macro because the usage data is recorded no
+    // more than once per second.
+    base::UmaHistogramEnumeration(
+        "Apps.AppListUsageByNewUsers",
+        AppListUsageStateByNewUsers::kNotUsedBeforeDestruction);
+  }
+
   session_manager::SessionManager::Get()->RemoveObserver(this);
 
   DCHECK_EQ(this, g_app_list_client_instance);
@@ -339,6 +353,13 @@
     // be both new. It should not happen in the real world.
     state_for_new_user_ = StateForNewUser();
   } else if (state_for_new_user_) {
+    if (!state_for_new_user_->showing_recorded) {
+      // We assume that the previous user before switching was new if
+      // `state_for_new_user_` is not null.
+      base::UmaHistogramEnumeration(
+          "Apps.AppListUsageByNewUsers",
+          AppListUsageStateByNewUsers::kNotUsedBeforeSwitchingAccounts);
+    }
     state_for_new_user_.reset();
   }
 
@@ -637,4 +658,7 @@
         /*sample=*/launcher_action_duration, kTimeMetricsMin, kTimeMetricsMax,
         kTimeMetricsBucketCount);
   }
+
+  base::UmaHistogramEnumeration("Apps.AppListUsageByNewUsers",
+                                AppListUsageStateByNewUsers::kUsed);
 }
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.h b/chrome/browser/ui/app_list/app_list_client_impl.h
index 8989d55..6eb2ddd 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.h
+++ b/chrome/browser/ui/app_list/app_list_client_impl.h
@@ -43,6 +43,27 @@
       public session_manager::SessionManagerObserver,
       public TemplateURLServiceObserver {
  public:
+  // Indicates the launcher usage state during the session started by a new user
+  // (i.e. the session completing the OOBE flow) but before any account
+  // switching. These are used in histograms, do not remove/renumber entries. If
+  // you're adding to this enum with the intention that it will be logged,
+  // update the AppListUsageStateByNewUsers enum listing in
+  // tools/metrics/histograms/enums.xml.
+  enum class AppListUsageStateByNewUsers {
+    // Launcher is used during the session started by a new user.
+    kUsed = 0,
+
+    // Launcher is not used before destruction. The destruction can be triggered
+    // in the following scenarios: logging out all account, shutting down the
+    // device and system crashes.
+    kNotUsedBeforeDestruction = 1,
+
+    // Launcher is not used before switching accounts.
+    kNotUsedBeforeSwitchingAccounts = 2,
+
+    kMaxValue = kNotUsedBeforeSwitchingAccounts,
+  };
+
   AppListClientImpl();
   AppListClientImpl(const AppListClientImpl&) = delete;
   AppListClientImpl& operator=(const AppListClientImpl&) = delete;
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
index d9581ac..201b1ea 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -667,10 +667,17 @@
     DurationBetweenSeesionActivationAndFirstLauncherShowingBrowserTest,
     MetricNotRecordedOnRegisteredAccount) {
   chromeos::UserAddingScreen::Get()->Start();
+
+  // Verify that the launcher usage state is recorded when switching accounts.
+  base::HistogramTester tester;
   AddUser(registered_user_id_);
+  tester.ExpectBucketCount(
+      "Apps.AppListUsageByNewUsers",
+      static_cast<int>(AppListClientImpl::AppListUsageStateByNewUsers::
+                           kNotUsedBeforeSwitchingAccounts),
+      1);
 
   // Verify that the metric is not recorded.
-  base::HistogramTester tester;
   ShowAppListAndVerify();
   tester.ExpectTotalCount(
       "Apps.TimeDurationBetweenNewUserSessionActivationAndFirstLauncherOpening",
@@ -695,3 +702,39 @@
       "Apps.TimeDurationBetweenNewUserSessionActivationAndFirstLauncherOpening",
       0);
 }
+
+class DurationBetweenSeesionActivationAndFirstLauncherShowingShutdownTest
+    : public DurationBetweenSeesionActivationAndFirstLauncherShowingBrowserTest {
+ public:
+  DurationBetweenSeesionActivationAndFirstLauncherShowingShutdownTest() =
+      default;
+  ~DurationBetweenSeesionActivationAndFirstLauncherShowingShutdownTest()
+      override = default;
+
+ protected:
+  // DurationBetweenSeesionActivationAndFirstLauncherShowingBrowserTest:
+  void SetUpOnMainThread() override {
+    DurationBetweenSeesionActivationAndFirstLauncherShowingBrowserTest::
+        SetUpOnMainThread();
+    histogram_tester_ = std::make_unique<base::HistogramTester>();
+  }
+
+  void TearDown() override {
+    histogram_tester_->ExpectBucketCount(
+        "Apps.AppListUsageByNewUsers",
+        static_cast<int>(AppListClientImpl::AppListUsageStateByNewUsers::
+                             kNotUsedBeforeDestruction),
+        1);
+    DurationBetweenSeesionActivationAndFirstLauncherShowingBrowserTest::
+        TearDown();
+  }
+
+  std::unique_ptr<base::HistogramTester> histogram_tester_;
+};
+
+// Verify that the launcher usage state is recorded when shutting down.
+IN_PROC_BROWSER_TEST_F(
+    DurationBetweenSeesionActivationAndFirstLauncherShowingShutdownTest,
+    NotUseLauncherBeforeShuttingDown) {
+  // Do nothing. Verify the histogram after the browser process is terminated.
+}
diff --git a/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc b/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc
index 042ac9d..4b40abd 100644
--- a/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc
@@ -6,10 +6,6 @@
 #include <vector>
 
 #include "ash/constants/ash_features.h"
-#include "ash/content/help_app_ui/help_app_manager.h"
-#include "ash/content/help_app_ui/help_app_manager_factory.h"
-#include "ash/content/help_app_ui/search/search.mojom.h"
-#include "ash/content/help_app_ui/search/search_handler.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
@@ -41,6 +37,10 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/components/help_app_ui/help_app_manager.h"
+#include "chromeos/components/help_app_ui/help_app_manager_factory.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h
index 60ef6f2..58098f3 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.h
+++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -12,7 +12,6 @@
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
 
 class AppListControllerDelegate;
diff --git a/chrome/browser/ui/app_list/search/help_app_provider.cc b/chrome/browser/ui/app_list/search/help_app_provider.cc
index be76028..b8abdd6 100644
--- a/chrome/browser/ui/app_list/search/help_app_provider.cc
+++ b/chrome/browser/ui/app_list/search/help_app_provider.cc
@@ -7,10 +7,6 @@
 #include <memory>
 
 #include "ash/constants/ash_features.h"
-#include "ash/content/help_app_ui/help_app_manager.h"
-#include "ash/content/help_app_ui/help_app_manager_factory.h"
-#include "ash/content/help_app_ui/search/search_handler.h"
-#include "ash/content/help_app_ui/url_constants.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_metrics.h"
@@ -32,6 +28,10 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/components/help_app_ui/help_app_manager.h"
+#include "chromeos/components/help_app_ui/help_app_manager_factory.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/app_list/search/help_app_provider.h b/chrome/browser/ui/app_list/search/help_app_provider.h
index b9b60d5..7908f0a2 100644
--- a/chrome/browser/ui/app_list/search/help_app_provider.h
+++ b/chrome/browser/ui/app_list/search/help_app_provider.h
@@ -8,12 +8,12 @@
 #include <string>
 #include <vector>
 
-#include "ash/content/help_app_ui/search/search.mojom.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
index 9277d36..623d93b 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
@@ -14,7 +14,6 @@
 #include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/file_manager/file_tasks_notifier.h"
 #include "chrome/browser/chromeos/file_manager/file_tasks_observer.h"
diff --git a/chrome/browser/ui/ash/ash_test_util.cc b/chrome/browser/ui/ash/ash_test_util.cc
index 5e21914..68968e22 100644
--- a/chrome/browser/ui/ash/ash_test_util.cc
+++ b/chrome/browser/ui/ash/ash_test_util.cc
@@ -59,15 +59,15 @@
   ASSERT_TRUE(wm::IsActiveWindow(window));
 
   SnapWaiter snap_waiter(window, type);
-  ASSERT_TRUE(type == chromeos::WindowStateType::kRightSnapped ||
-              type == chromeos::WindowStateType::kLeftSnapped);
+  ASSERT_TRUE(type == chromeos::WindowStateType::kSecondarySnapped ||
+              type == chromeos::WindowStateType::kPrimarySnapped);
 
   // Early return if it's already snapped.
   if (snap_waiter.IsSnapped())
     return;
 
   ui_controls::SendKeyPress(window,
-                            type == chromeos::WindowStateType::kLeftSnapped
+                            type == chromeos::WindowStateType::kPrimarySnapped
                                 ? ui::VKEY_OEM_4
                                 : ui::VKEY_OEM_6,
                             /*control=*/false,
diff --git a/chrome/browser/ui/ash/holding_space/BUILD.gn b/chrome/browser/ui/ash/holding_space/BUILD.gn
index 3948a1e..c2dca4b6 100644
--- a/chrome/browser/ui/ash/holding_space/BUILD.gn
+++ b/chrome/browser/ui/ash/holding_space/BUILD.gn
@@ -17,6 +17,7 @@
     ":test_support",
     "//ash:test_support",
     "//ash/public/cpp",
+    "//ash/public/cpp/holding_space:test_support",
     "//base/test:test_support",
     "//chrome/browser",
     "//chrome/browser/ash/crosapi",
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc b/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc
index ddbd37e..93730a0a 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc
@@ -223,25 +223,11 @@
           std::move(callback)));
 }
 
-void HoldingSpaceClientImpl::ShowItemInFolder(const HoldingSpaceItem& item,
-                                              SuccessCallback callback) {
-  holding_space_metrics::RecordItemAction(
-      {&item}, holding_space_metrics::ItemAction::kShowInFolder);
-
-  if (item.file_path().empty()) {
-    std::move(callback).Run(/*success=*/false);
-    return;
-  }
-
-  file_manager::util::ShowItemInFolder(
-      profile_, item.file_path(),
-      base::BindOnce(
-          [](SuccessCallback callback,
-             platform_util::OpenOperationResult result) {
-            const bool success = result == platform_util::OPEN_SUCCEEDED;
-            std::move(callback).Run(success);
-          },
-          std::move(callback)));
+void HoldingSpaceClientImpl::PauseItems(
+    const std::vector<const HoldingSpaceItem*>& items) {
+  auto* const service = GetHoldingSpaceKeyedService(profile_);
+  for (const HoldingSpaceItem* item : items)
+    service->PauseItem(item);
 }
 
 void HoldingSpaceClientImpl::PinFiles(
@@ -278,6 +264,34 @@
     service->AddPinnedFiles(file_system_urls);
 }
 
+void HoldingSpaceClientImpl::ResumeItems(
+    const std::vector<const HoldingSpaceItem*>& items) {
+  auto* const service = GetHoldingSpaceKeyedService(profile_);
+  for (const HoldingSpaceItem* item : items)
+    service->ResumeItem(item);
+}
+
+void HoldingSpaceClientImpl::ShowItemInFolder(const HoldingSpaceItem& item,
+                                              SuccessCallback callback) {
+  holding_space_metrics::RecordItemAction(
+      {&item}, holding_space_metrics::ItemAction::kShowInFolder);
+
+  if (item.file_path().empty()) {
+    std::move(callback).Run(/*success=*/false);
+    return;
+  }
+
+  file_manager::util::ShowItemInFolder(
+      profile_, item.file_path(),
+      base::BindOnce(
+          [](SuccessCallback callback,
+             platform_util::OpenOperationResult result) {
+            const bool success = result == platform_util::OPEN_SUCCEEDED;
+            std::move(callback).Run(success);
+          },
+          std::move(callback)));
+}
+
 void HoldingSpaceClientImpl::UnpinItems(
     const std::vector<const HoldingSpaceItem*>& items) {
   std::vector<storage::FileSystemURL> file_system_urls;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_client_impl.h b/chrome/browser/ui/ash/holding_space/holding_space_client_impl.h
index a0c1c37..1c1c1ec 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_client_impl.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_client_impl.h
@@ -34,9 +34,11 @@
   void OpenItems(const std::vector<const HoldingSpaceItem*>& items,
                  SuccessCallback callback) override;
   void OpenMyFiles(SuccessCallback callback) override;
-  void ShowItemInFolder(const HoldingSpaceItem&, SuccessCallback) override;
+  void PauseItems(const std::vector<const HoldingSpaceItem*>& items) override;
   void PinFiles(const std::vector<base::FilePath>& file_paths) override;
   void PinItems(const std::vector<const HoldingSpaceItem*>& items) override;
+  void ResumeItems(const std::vector<const HoldingSpaceItem*>& items) override;
+  void ShowItemInFolder(const HoldingSpaceItem&, SuccessCallback) override;
   void UnpinItems(const std::vector<const HoldingSpaceItem*>& items) override;
 
  private:
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc
index 1ac82d02..ad05b18 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.cc
@@ -62,9 +62,17 @@
   ~InProgressDownload() override = default;
 
   // Cancels the underlying `download_item_`. NOTE: This is expected to be
-  // invoked in direct response to an explicit user action.
+  // invoked in direct response to an explicit user action and will result in
+  // the destruction of `this`.
   void Cancel() { download_item_->Cancel(/*from_user=*/true); }
 
+  // Pauses the underlying `download_item_`.
+  void Pause() { download_item_->Pause(); }
+
+  // Resumes the underlying `download_item_`. NOTE: This is expected to be
+  // invoked in direct response to an explicit user action.
+  void Resume() { download_item_->Resume(/*from_user=*/true); }
+
   // Returns the file path associated with the underlying `download_item_`.
   // NOTE: The file path may be empty before a target file path has been picked.
   const base::FilePath& GetFilePath() const {
@@ -87,6 +95,9 @@
     return progress;
   }
 
+  // Returns whether the underlying `download_item_` is paused.
+  bool IsPaused() const { return download_item_->IsPaused(); }
+
   // Associates this in-progress download with the specified in-progress
   // `holding_space_item`. NOTE: This association may be performed only once.
   void SetHoldingSpaceItem(const HoldingSpaceItem* holding_space_item) {
@@ -176,6 +187,28 @@
   }
 }
 
+// TODO(crbug.com/1184438): Handle Lacros downloads.
+void HoldingSpaceDownloadsDelegate::Pause(const HoldingSpaceItem* item) {
+  DCHECK(HoldingSpaceItem::IsDownload(item->type()));
+  for (const auto& in_progress_download : in_progress_downloads_) {
+    if (in_progress_download->GetHoldingSpaceItem() == item) {
+      in_progress_download->Pause();
+      return;
+    }
+  }
+}
+
+// TODO(crbug.com/1184438): Handle Lacros downloads.
+void HoldingSpaceDownloadsDelegate::Resume(const HoldingSpaceItem* item) {
+  DCHECK(HoldingSpaceItem::IsDownload(item->type()));
+  for (const auto& in_progress_download : in_progress_downloads_) {
+    if (in_progress_download->GetHoldingSpaceItem() == item) {
+      in_progress_download->Resume();
+      return;
+    }
+  }
+}
+
 void HoldingSpaceDownloadsDelegate::Init() {
   // ARC downloads.
   if (features::IsHoldingSpaceArcIntegrationEnabled()) {
@@ -348,11 +381,14 @@
   }
 
   // Update.
+  // TODO(crbug.com/1213274): Perform a single atomic update of all attributes.
   model()->UpdateBackingFileForItem(
       in_progress_download->GetHoldingSpaceItem()->id(),
       in_progress_download->GetFilePath(),
       holding_space_util::ResolveFileSystemUrl(
           profile(), in_progress_download->GetFilePath()));
+  model()->UpdatePauseForItem(in_progress_download->GetHoldingSpaceItem()->id(),
+                              in_progress_download->IsPaused());
   model()->UpdateProgressForItem(
       in_progress_download->GetHoldingSpaceItem()->id(),
       in_progress_download->GetProgress());
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.h b/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.h
index f0c0d564..2cd6f3ec 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_downloads_delegate.h
@@ -44,8 +44,10 @@
   static void SetDownloadManagerForTesting(
       content::DownloadManager* download_manager);
 
-  // Attempts to cancel the download underlying the specified `item`.
+  // Attempts to cancel/pause/resume the download underlying the given `item`.
   void Cancel(const HoldingSpaceItem* item);
+  void Pause(const HoldingSpaceItem* item);
+  void Resume(const HoldingSpaceItem* item);
 
  private:
   class InProgressDownload;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
index f947157..b5bdced 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -306,6 +306,18 @@
     downloads_delegate_->Cancel(item);
 }
 
+void HoldingSpaceKeyedService::PauseItem(const HoldingSpaceItem* item) {
+  // Currently it is only possible to pause download type items.
+  if (HoldingSpaceItem::IsDownload(item->type()) && downloads_delegate_)
+    downloads_delegate_->Pause(item);
+}
+
+void HoldingSpaceKeyedService::ResumeItem(const HoldingSpaceItem* item) {
+  // Currently it is only possible to resume download type items.
+  if (HoldingSpaceItem::IsDownload(item->type()) && downloads_delegate_)
+    downloads_delegate_->Resume(item);
+}
+
 void HoldingSpaceKeyedService::Shutdown() {
   ShutdownDelegates();
 }
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
index ec1baef..1532126 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
@@ -120,8 +120,10 @@
                      const base::FilePath& file_path,
                      const absl::optional<float>& progress = 1.f);
 
-  // Attempts to cancel the specified holding space `item`.
+  // Attempts to cancel/pause/resume the specified holding space `item`.
   void CancelItem(const HoldingSpaceItem* item);
+  void PauseItem(const HoldingSpaceItem* item);
+  void ResumeItem(const HoldingSpaceItem* item);
 
   // Returns the `profile_` associated with this service.
   Profile* profile() { return profile_; }
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
index d8d6afb7..c6be0d9 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/holding_space/holding_space_item.h"
 #include "ash/public/cpp/holding_space/holding_space_model.h"
 #include "ash/public/cpp/holding_space/holding_space_model_observer.h"
+#include "ash/public/cpp/holding_space/mock_holding_space_model_observer.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
@@ -52,25 +53,6 @@
 // enum.
 enum class FileSystemType { kDownloads, kDriveFs };
 
-// Mocks -----------------------------------------------------------------------
-
-// Mock observer which can be used to set expectations about model behavior.
-class MockHoldingSpaceModelObserver : public HoldingSpaceModelObserver {
- public:
-  MOCK_METHOD(void,
-              OnHoldingSpaceItemsAdded,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              OnHoldingSpaceItemsRemoved,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              OnHoldingSpaceItemInitialized,
-              (const HoldingSpaceItem* item),
-              (override));
-};
-
 // Helpers ---------------------------------------------------------------------
 
 // Returns the path of the downloads mount point for the given `profile`.
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
index 6ec3a2c..c4c7ecb 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
@@ -19,6 +19,8 @@
 #include "ash/public/cpp/holding_space/holding_space_model_observer.h"
 #include "ash/public/cpp/holding_space/holding_space_prefs.h"
 #include "ash/public/cpp/holding_space/holding_space_test_api.h"
+#include "ash/public/cpp/holding_space/mock_holding_space_client.h"
+#include "ash/public/cpp/holding_space/mock_holding_space_model_observer.h"
 #include "base/callback_helpers.h"
 #include "base/containers/contains.h"
 #include "base/files/file_util.h"
@@ -236,69 +238,6 @@
               (override));
 };
 
-class MockHoldingSpaceClient : public HoldingSpaceClient {
- public:
-  MOCK_METHOD(void,
-              AddScreenshot,
-              (const base::FilePath& file_path),
-              (override));
-  MOCK_METHOD(void,
-              AddScreenRecording,
-              (const base::FilePath& file_path),
-              (override));
-  MOCK_METHOD(void,
-              CancelItems,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              CopyImageToClipboard,
-              (const HoldingSpaceItem& item, SuccessCallback callback),
-              (override));
-  MOCK_METHOD(base::FilePath,
-              CrackFileSystemUrl,
-              (const GURL& file_system_url),
-              (const, override));
-  MOCK_METHOD(void, OpenDownloads, (SuccessCallback callback), (override));
-  MOCK_METHOD(void, OpenMyFiles, (SuccessCallback callback), (override));
-  MOCK_METHOD(void,
-              OpenItems,
-              (const std::vector<const HoldingSpaceItem*>& items,
-               SuccessCallback callback),
-              (override));
-  MOCK_METHOD(void,
-              ShowItemInFolder,
-              (const HoldingSpaceItem& item, SuccessCallback callback),
-              (override));
-  MOCK_METHOD(void,
-              PinFiles,
-              (const std::vector<base::FilePath>& file_paths),
-              (override));
-  MOCK_METHOD(void,
-              PinItems,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              UnpinItems,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-};
-
-class MockHoldingSpaceModelObserver : public HoldingSpaceModelObserver {
- public:
-  MOCK_METHOD(void,
-              OnHoldingSpaceItemsAdded,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              OnHoldingSpaceItemsRemoved,
-              (const std::vector<const HoldingSpaceItem*>& items),
-              (override));
-  MOCK_METHOD(void,
-              OnHoldingSpaceItemInitialized,
-              (const HoldingSpaceItem* item),
-              (override));
-};
-
 // DropSenderView --------------------------------------------------------------
 
 class DropSenderView : public views::WidgetDelegateView,
@@ -1353,10 +1292,38 @@
     ON_CALL(*mock_download_item, GetState)
         .WillByDefault(testing::Return(state));
 
+    // Mock `download::DownloadItem::IsPaused()`.
+    auto paused = std::make_unique<bool>(false);
+    ON_CALL(*mock_download_item, IsPaused)
+        .WillByDefault(testing::Invoke(
+            [paused_ptr = paused.get()]() { return *paused_ptr; }));
+
+    // Create a callback which can be run to set `paused` state and which
+    // mirrors production behavior by notifying observers on change.
+    auto set_paused = base::BindRepeating(
+        [](download::MockDownloadItem* mock_download_item, bool* paused,
+           bool new_paused) {
+          if (*paused != new_paused) {
+            *paused = new_paused;
+            mock_download_item->NotifyObserversDownloadUpdated();
+          }
+        },
+        base::Unretained(mock_download_item.get()),
+        base::Owned(std::move(paused)));
+
+    // Mock `download::DownloadItem::Pause()`.
+    ON_CALL(*mock_download_item, Pause).WillByDefault([set_paused]() {
+      set_paused.Run(true);
+    });
+
     // Mock `download::DownloadItem::PercentComplete()`.
     ON_CALL(*mock_download_item, PercentComplete)
         .WillByDefault(testing::Return(percent_complete));
 
+    // Mock `download::DownloadItem::Resume()`.
+    ON_CALL(*mock_download_item, Resume(/*from_user=*/testing::Eq(true)))
+        .WillByDefault([set_paused]() { set_paused.Run(false); });
+
     // Notify observers of the created download.
     for (auto& observer : download_manager_observers_)
       observer.OnDownloadCreated(&download_manager_, mock_download_item.get());
@@ -1468,6 +1435,125 @@
                                                   in_progress_download_id));
 }
 
+// Base class for tests of the pause or resume commands, parameterized by which
+// command to use. This will either be `kPauseItem` or `kResumeItem`.
+class HoldingSpaceUiPauseOrResumeBrowserTest
+    : public HoldingSpaceUiInProgressDownloadsBrowserTest,
+      public testing::WithParamInterface<HoldingSpaceCommandId> {
+ public:
+  HoldingSpaceUiPauseOrResumeBrowserTest() {
+    const HoldingSpaceCommandId command_id(GetPauseOrResumeCommandId());
+    EXPECT_TRUE(command_id == HoldingSpaceCommandId::kPauseItem ||
+                command_id == HoldingSpaceCommandId::kResumeItem);
+  }
+
+  // Returns either `kPauseItem` or `kResumeItem` depending on parameterization.
+  HoldingSpaceCommandId GetPauseOrResumeCommandId() const { return GetParam(); }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    HoldingSpaceUiPauseOrResumeBrowserTest,
+    testing::ValuesIn({HoldingSpaceCommandId::kPauseItem,
+                       HoldingSpaceCommandId::kResumeItem}));
+
+// Verifies that pausing or resuming holding space items works as intended.
+IN_PROC_BROWSER_TEST_P(HoldingSpaceUiPauseOrResumeBrowserTest,
+                       PauseOrResumeItem) {
+  // Use zero animation duration so that UI updates are immediate.
+  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+  // Create an in-progress download which may or may not be paused depending
+  // on parameterization.
+  auto in_progress_download =
+      CreateMockDownloadItem(download::DownloadItem::IN_PROGRESS, CreateFile(),
+                             /*percent_complete=*/0);
+  if (GetPauseOrResumeCommandId() == HoldingSpaceCommandId::kResumeItem)
+    in_progress_download->Pause();
+  in_progress_download->NotifyObserversDownloadUpdated();
+
+  // Create a completed download.
+  // NOTE: In production, the download manager will create COMPLETE download
+  // items from previous sessions during initialization, so we ignore them. To
+  // match production behavior, create an IN_PROGRESS download item and only
+  // then update it to COMPLETE state.
+  auto completed_download =
+      CreateMockDownloadItem(download::DownloadItem::IN_PROGRESS, CreateFile(),
+                             /*percent_complete=*/0);
+  ON_CALL(*completed_download, GetState())
+      .WillByDefault(testing::Return(download::DownloadItem::COMPLETE));
+  ON_CALL(*completed_download, PercentComplete())
+      .WillByDefault(testing::Return(100));
+  completed_download->NotifyObserversDownloadUpdated();
+
+  // Show holding space UI.
+  test_api().Show();
+  ASSERT_TRUE(test_api().IsShowing());
+
+  // Expect two download chips, one for each created download item.
+  std::vector<views::View*> download_chips = test_api().GetDownloadChips();
+  ASSERT_EQ(download_chips.size(), 2u);
+
+  // Cache download chips. NOTE: Chips are displayed in reverse order of their
+  // underlying holding space item creation.
+  views::View* const completed_download_chip = download_chips.at(0);
+  views::View* const in_progress_download_chip = download_chips.at(1);
+
+  // Right click the `completed_download_chip`. Because the underlying download
+  // is completed, the context menu should *not* contain a "Pause" or "Resume"
+  // command.
+  RightClick(completed_download_chip);
+  ASSERT_FALSE(SelectMenuItemWithCommandId(GetPauseOrResumeCommandId()));
+
+  // Close the context menu and control-right click the
+  // `in_progress_download_chip`. Because the `completed_download_chip` is still
+  // selected and its underlying download is completed, the context menu should
+  // *not* contain a "Pause" or "Resume" command.
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE);
+  RightClick(in_progress_download_chip, ui::EF_CONTROL_DOWN);
+  ASSERT_FALSE(SelectMenuItemWithCommandId(GetPauseOrResumeCommandId()));
+
+  // Close the context menu, press the `in_progress_download_chip` and then
+  // right click it. Because the `in_progress_download_chip` is the only chip
+  // selected and its underlying download is in-progress, the context menu
+  // should contain a "Pause" or "Resume" command.
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE);
+  Click(in_progress_download_chip);
+  RightClick(in_progress_download_chip);
+  ASSERT_TRUE(SelectMenuItemWithCommandId(GetPauseOrResumeCommandId()));
+
+  // Bind an observer to watch for updates to the holding space model.
+  testing::NiceMock<MockHoldingSpaceModelObserver> mock;
+  base::ScopedObservation<HoldingSpaceModel, HoldingSpaceModelObserver>
+      observer{&mock};
+  observer.Observe(HoldingSpaceController::Get()->model());
+
+  // Press ENTER to execute the "Pause" or "Resume" command, expecting and
+  // waiting for the in-progress download item to be updated in the holding
+  // space model.
+  base::RunLoop run_loop;
+  const bool was_paused = in_progress_download->IsPaused();
+  EXPECT_CALL(mock, OnHoldingSpaceItemUpdated)
+      .WillOnce([&](const HoldingSpaceItem* item) {
+        EXPECT_EQ(item->id(),
+                  test_api().GetHoldingSpaceItemId(in_progress_download_chip));
+        EXPECT_EQ(item->IsPaused(), !was_paused);
+        run_loop.Quit();
+      });
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN);
+  run_loop.Run();
+
+  // Verify that there are still two download chips.
+  download_chips = test_api().GetDownloadChips();
+  ASSERT_EQ(download_chips.size(), 2u);
+
+  // The two download chips present should still be the original chips for the
+  // completed download and the (now paused) in-progress download.
+  EXPECT_EQ(download_chips.at(0), completed_download_chip);
+  EXPECT_EQ(download_chips.at(1), in_progress_download_chip);
+}
+
 // Base class for holding space UI browser tests that take screenshots.
 // Parameterized by whether or not `features::CaptureMode` is enabled.
 class HoldingSpaceUiScreenshotBrowserTest
diff --git a/chrome/browser/ui/cocoa/tab_contents/web_contents_view_mac_interactive_uitest.mm b/chrome/browser/ui/cocoa/tab_contents/web_contents_view_mac_interactive_uitest.mm
index 89a3dba..0e7c398 100644
--- a/chrome/browser/ui/cocoa/tab_contents/web_contents_view_mac_interactive_uitest.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/web_contents_view_mac_interactive_uitest.mm
@@ -6,7 +6,6 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "base/run_loop.h"
-#include "base/scoped_observation.h"
 #include "base/test/bind.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -30,7 +29,7 @@
 class TabRemovedWaiter : public TabStripModelObserver {
  public:
   explicit TabRemovedWaiter(Browser* browser) {
-    observation_.Observe(browser->tab_strip_model());
+    browser->tab_strip_model()->AddObserver(this);
   }
   TabRemovedWaiter(const TabRemovedWaiter&) = delete;
   TabRemovedWaiter& operator=(const TabRemovedWaiter&) = delete;
@@ -49,9 +48,6 @@
 
  private:
   base::RunLoop run_loop_;
-
-  base::ScopedObservation<TabStripModel, TabStripModelObserver> observation_{
-      this};
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index 79920cf..31c33b9 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/cxx17_backports.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 23b9226..debdcea 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -131,6 +131,7 @@
 #include "chrome/browser/video_tutorials/video_tutorial_tab_helper.h"
 #include "components/autofill_assistant/browser/features.h"
 #else
+#include "chrome/browser/accuracy_tips/accuracy_service_factory.h"
 #include "chrome/browser/banners/app_banner_manager_desktop.h"
 #include "chrome/browser/tab_contents/form_interaction_tab_helper.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
@@ -140,6 +141,7 @@
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/browser/ui/sync/browser_synced_tab_delegate.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "components/accuracy_tips/accuracy_web_contents_observer.h"
 #include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "components/zoom/zoom_controller.h"
@@ -374,6 +376,10 @@
         web_contents);
   }
 #else
+  if (accuracy_tips::AccuracyWebContentsObserver::IsEnabled(web_contents)) {
+    accuracy_tips::AccuracyWebContentsObserver::CreateForWebContents(
+        web_contents, AccuracyServiceFactory::GetForProfile(profile));
+  }
   if (web_app::AreWebAppsUserInstallable(profile))
     webapps::AppBannerManagerDesktop::CreateForWebContents(web_contents);
   BookmarkTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 4e2a3e6..b7258e2 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -18,7 +18,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
+#include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
@@ -835,14 +836,27 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModel);
 };
 
-// Forbid construction of ScopedObserver with TabStripModel:
-// TabStripModelObserver already implements ScopedObserver's functionality
-// natively.
+// Forbid construction of ScopedObservation and ScopedMultiSourceObservation
+// with TabStripModel: TabStripModelObserver already implements their
+// functionality natively.
+namespace base {
+
 template <>
-class ScopedObserver<TabStripModel, TabStripModelObserver> {
+class ScopedObservation<TabStripModel, TabStripModelObserver> {
  public:
   // Deleting the constructor gives a clear error message traceable back to here.
-  explicit ScopedObserver(TabStripModelObserver* observer) = delete;
+  explicit ScopedObservation(TabStripModelObserver* observer) = delete;
 };
 
+template <>
+class ScopedMultiSourceObservation<TabStripModel, TabStripModelObserver> {
+ public:
+  // Deleting the constructor gives a clear error message traceable back to
+  // here.
+  explicit ScopedMultiSourceObservation(TabStripModelObserver* observer) =
+      delete;
+};
+
+}  // namespace base
+
 #endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
diff --git a/chrome/browser/ui/thumbnails/thumbnail_image_unittest.cc b/chrome/browser/ui/thumbnails/thumbnail_image_unittest.cc
index a9f201f..d4a24cd 100644
--- a/chrome/browser/ui/thumbnails/thumbnail_image_unittest.cc
+++ b/chrome/browser/ui/thumbnails/thumbnail_image_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "base/test/task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h
index 287c351..907f350 100644
--- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h
+++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/thumbnails/thumbnail_capture_info.h"
 #include "chrome/browser/ui/thumbnails/thumbnail_image.h"
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index e10ed7e..c9346594 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -112,16 +112,7 @@
 const base::Feature kTabGroupsNewBadgePromo{"TabGroupsNewBadgePromo",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables popup cards containing tab information when hovering over a tab.
-// https://crbug.com/910739
-const base::Feature kTabHoverCards{"TabHoverCards",
-                                   base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Parameter name used for tab hover cards user study.
-// TODO(corising): Removed this after tab hover cards user study.
-const char kTabHoverCardsFeatureParameterName[] = "setting";
-
-// Enables preview images in hover cards. See kTabHoverCards.
+// Enables preview images in tab-hover cards.
 // https://crbug.com/928954
 const base::Feature kTabHoverCardImages{"TabHoverCardImages",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 92b5d811..12369a4 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -70,9 +70,6 @@
 
 extern const base::Feature kTabGroupsNewBadgePromo;
 
-extern const base::Feature kTabHoverCards;
-extern const char kTabHoverCardsFeatureParameterName[];
-
 extern const base::Feature kTabHoverCardImages;
 extern const char kTabHoverCardImagesNotReadyDelayParameterName[];
 extern const char kTabHoverCardImagesLoadingDelayParameterName[];
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
index 299cf4ab..dcf3df4e 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
@@ -90,7 +90,7 @@
   window->SetBounds(restored_bounds);
 
   // Snap the window to the left.
-  const ash::WMEvent left_snap_event(ash::WM_EVENT_SNAP_LEFT);
+  const ash::WMEvent left_snap_event(ash::WM_EVENT_SNAP_PRIMARY);
   ash::WindowState::Get(window)->OnWMEvent(&left_snap_event);
   const gfx::Size snapped_size = window->GetBoundsInScreen().size();
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 14e0f078..365ef7d 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -104,8 +104,8 @@
   chromeos::WindowStateType type =
       GetWindowForTabDraggingProperties(context)->GetProperty(
           chromeos::kWindowStateTypeKey);
-  return type == chromeos::WindowStateType::kLeftSnapped ||
-         type == chromeos::WindowStateType::kRightSnapped;
+  return type == chromeos::WindowStateType::kPrimarySnapped ||
+         type == chromeos::WindowStateType::kSecondarySnapped;
 }
 
 // In Chrome OS tablet mode, when dragging a tab/tabs around, the desired
diff --git a/chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc b/chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc
index 660bf1e..02eff7c 100644
--- a/chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/read_later_toolbar_button.cc
@@ -65,7 +65,7 @@
   contents_wrapper_->ReloadWebContents();
 
   SetVectorIcons(kSidePanelIcon, kSidePanelTouchIcon);
-  SetTooltipText(l10n_util::GetStringUTF16(IDS_READ_LATER_TITLE));
+  SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_SIDE_PANEL_SHOW));
 }
 
 ReadLaterToolbarButton::~ReadLaterToolbarButton() = default;
@@ -84,6 +84,7 @@
         browser_view->right_aligned_side_panel()->AddChildView(
             std::move(webview));
     SetHighlighted(true);
+    SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_SIDE_PANEL_HIDE));
   } else {
     browser_view->right_aligned_side_panel()->RemoveChildViewT(
         side_panel_webview_);
@@ -91,5 +92,6 @@
     // TODO(pbos): Observe read_later_side_panel_bubble_ so we don't need to
     // SetHighlighted(false) here.
     SetHighlighted(false);
+    SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_SIDE_PANEL_SHOW));
   }
 }
diff --git a/chrome/browser/ui/web_applications/web_app_profile_deletion_browsertest.cc b/chrome/browser/ui/web_applications/web_app_profile_deletion_browsertest.cc
index 54eb190..bbae920 100644
--- a/chrome/browser/ui/web_applications/web_app_profile_deletion_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_profile_deletion_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include "base/callback_helpers.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "base/test/bind.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.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 2af0f67..4a2a142 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -152,8 +152,6 @@
 #include "ash/components/os_feedback_ui/url_constants.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
-#include "ash/content/help_app_ui/help_app_ui.h"
-#include "ash/content/help_app_ui/url_constants.h"
 #include "ash/content/scanning/scanning_ui.h"
 #include "ash/content/scanning/url_constants.h"
 #include "ash/content/shimless_rma/shimless_rma.h"
@@ -228,6 +226,8 @@
 #include "chromeos/components/eche_app_ui/eche_app_manager.h"
 #include "chromeos/components/eche_app_ui/eche_app_ui.h"
 #include "chromeos/components/eche_app_ui/url_constants.h"
+#include "chromeos/components/help_app_ui/help_app_ui.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/media_app_ui/media_app_ui.h"
 #include "chromeos/components/media_app_ui/url_constants.h"
 #include "chromeos/components/multidevice/debug_webui/proximity_auth_ui.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h
index ba724c6..8a978fee 100644
--- a/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h
@@ -44,7 +44,7 @@
  public:
   using TView = ActiveDirectoryPasswordChangeView;
 
-  explicit ActiveDirectoryPasswordChangeScreenHandler(
+  ActiveDirectoryPasswordChangeScreenHandler(
       JSCallsContainer* js_calls_container);
   ~ActiveDirectoryPasswordChangeScreenHandler() override;
 
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index fadb41f..1dba26ec 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -113,13 +113,13 @@
     deps += [
       "//ash/components/os_feedback_ui",
       "//ash/constants",
-      "//ash/content/help_app_ui",
       "//ash/content/shimless_rma",
       "//ash/content/shortcut_customization_ui",
       "//ash/public/cpp",
       "//chromeos/components/camera_app_ui",
       "//chromeos/components/connectivity_diagnostics",
       "//chromeos/components/eche_app_ui",
+      "//chromeos/components/help_app_ui",
       "//chromeos/components/media_app_ui",
       "//chromeos/components/personalization_app",
       "//chromeos/strings",
diff --git a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
index f24de084..dee1553 100644
--- a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
@@ -59,7 +59,6 @@
 #include "ash/components/os_feedback_ui/url_constants.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
-#include "ash/content/help_app_ui/url_constants.h"
 #include "ash/content/shimless_rma/url_constants.h"
 #include "ash/content/shortcut_customization_ui/url_constants.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
@@ -81,6 +80,7 @@
 #include "chrome/browser/web_applications/components/web_app_id_constants.h"
 #include "chromeos/components/camera_app_ui/url_constants.h"
 #include "chromeos/components/connectivity_diagnostics/url_constants.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/media_app_ui/url_constants.h"
 #include "chromeos/components/personalization_app/personalization_app_url_constants.h"
 #include "chromeos/strings/grit/chromeos_strings.h"  // nogncheck
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index e8041c5..3bd9bbf 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1622613557-e3441127fc5b5e1f9dc14f3decf2df5c42d1c176.profdata
+chrome-win32-master-1622635148-895a7a9b984ca2b99a4b00b2a04fc8e55c529fad.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index afc6bae7..2da6b3a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1622624342-981f1696f5f15ad031309647a13a21a6ff6ab5aa.profdata
+chrome-win64-master-1622635148-ba23959f0a77f895fe0cf2da1fc8384a42cf7236.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 2f13e2f..b0fe476b 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -186,9 +186,6 @@
     }
     if (is_chromeos_ash) {
       sources += [
-        "$root_gen_dir/ash/ash_help_app_bundle_resources.pak",
-        "$root_gen_dir/ash/ash_help_app_kids_magazine_bundle_resources.pak",
-        "$root_gen_dir/ash/ash_help_app_resources.pak",
         "$root_gen_dir/ash/ash_os_feedback_resources.pak",
         "$root_gen_dir/ash/ash_scanning_app_resources.pak",
         "$root_gen_dir/ash/ash_shimless_rma_resources.pak",
@@ -211,6 +208,9 @@
         "$root_gen_dir/chromeos/chromeos_diagnostics_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_eche_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_eche_bundle_resources.pak",
+        "$root_gen_dir/chromeos/chromeos_help_app_bundle_resources.pak",
+        "$root_gen_dir/chromeos/chromeos_help_app_kids_magazine_bundle_resources.pak",
+        "$root_gen_dir/chromeos/chromeos_help_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_media_app_bundle_resources.pak",
         "$root_gen_dir/chromeos/chromeos_media_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_personalization_app_resources.pak",
@@ -222,9 +222,6 @@
         "$root_gen_dir/ui/file_manager/file_manager_resources.pak",
       ]
       deps += [
-        "//ash/components/resources:help_app_bundle_resources",
-        "//ash/components/resources:help_app_kids_magazine_bundle_resources",
-        "//ash/components/resources:help_app_resources",
         "//ash/components/resources:os_feedback_resources",
         "//ash/components/resources:scanning_app_resources",
         "//ash/components/resources:shimless_rma_resources",
@@ -250,6 +247,9 @@
         "//chromeos/resources:diagnostics_app_resources",
         "//chromeos/resources:eche_app_resources",
         "//chromeos/resources:eche_bundle_resources",
+        "//chromeos/resources:help_app_bundle_resources",
+        "//chromeos/resources:help_app_kids_magazine_bundle_resources",
+        "//chromeos/resources:help_app_resources",
         "//chromeos/resources:media_app_bundle_resources",
         "//chromeos/resources:media_app_resources",
         "//chromeos/resources:personalization_app_resources",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 2b64151..784ec2e0 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -875,6 +875,11 @@
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
+#if defined(OS_ANDROID)
+const base::Feature kShareUsageRanking{"ShareUsageRanking",
+                                       base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 #if defined(OS_MAC)
 // Enables the "this OS is obsolete" infobar on Mac 10.10.
 // TODO(ellyjones): Remove this after the last 10.10 release.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 388c9bb2..4718253 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -587,6 +587,11 @@
 extern const base::Feature kChromeOSSharingHub;
 #endif
 
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kShareUsageRanking;
+#endif
+
 #if defined(OS_MAC)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kShow10_10ObsoleteInfobar;
diff --git a/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc b/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc
index 2f62e9e..9d9d887 100644
--- a/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc
+++ b/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc
@@ -24,10 +24,6 @@
     RobotsRulesParser::CheckResult check_result) {
   switch (check_result) {
     case RobotsRulesParser::CheckResult::kAllowed:
-      if (ShouldEnableLoginRobotsCheckedImageCompression() &&
-          !ShouldCompressRedirectSubresource()) {
-        return SubresourceRedirectResult::kIneligibleCompressionDisabled;
-      }
       return SubresourceRedirectResult::kRedirectable;
     case RobotsRulesParser::CheckResult::kDisallowed:
     case RobotsRulesParser::CheckResult::kInvalidated:
diff --git a/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc b/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc
index b34afbe5..5a63ed3c 100644
--- a/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc
+++ b/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc
@@ -93,8 +93,6 @@
 
   if (public_image_urls_->find(GetURLForPublicDecision(url)) !=
       public_image_urls_->end()) {
-    if (!ShouldCompressRedirectSubresource())
-      return SubresourceRedirectResult::kIneligibleCompressionDisabled;
     return SubresourceRedirectResult::kRedirectable;
   }
 
@@ -162,7 +160,6 @@
     case SubresourceRedirectResult::kIneligibleRedirectFailed:
     case SubresourceRedirectResult::kIneligibleBlinkDisallowed:
     case SubresourceRedirectResult::kIneligibleSubframeResource:
-    case SubresourceRedirectResult::kIneligibleCompressionDisabled:
       public_image_compression_data_use.SetIneligibleOtherImageBytes(
           content_length);
       break;
diff --git a/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc b/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
index 983fe04..eb139e4 100644
--- a/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
+++ b/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
@@ -150,6 +150,9 @@
   if (IsCompressionServerOrigin(request->url))
     return;
 
+  if (!ShouldCompressRedirectSubresource())
+    return;
+
   if (login_robots_compression_metrics_)
     login_robots_compression_metrics_->NotifyRequestStart();
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 59420bf..321dfac 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2128,7 +2128,6 @@
         "//ash/app_list/model:app_list_model",
         "//ash/components/audio",
         "//ash/components/os_feedback_ui:os_feedback_ui",
-        "//ash/content/help_app_ui",
         "//ash/content/scanning",
         "//ash/content/shimless_rma",
         "//ash/content/shortcut_customization_ui",
@@ -2162,6 +2161,7 @@
         "//chromeos/components/drivefs:test_support",
         "//chromeos/components/drivefs/mojom",
         "//chromeos/components/eche_app_ui",
+        "//chromeos/components/help_app_ui",
         "//chromeos/components/media_app_ui",
         "//chromeos/components/media_app_ui:browser_test_support",
         "//chromeos/components/print_management",
@@ -2303,9 +2303,9 @@
       ]
       if (is_chromeos_ash) {
         deps += [
-          "//ash/content/help_app_ui:browser_tests_js",
           "//chrome/browser/resources/gaia_auth_host:browser_tests",
           "//chromeos/components/eche_app_ui:browser_tests_js",
+          "//chromeos/components/help_app_ui:browser_tests_js",
           "//chromeos/components/media_app_ui:browser_tests_js",
           "//chromeos/components/personalization_app:browser_tests_js",
           "//chromeos/components/system_apps:browser_tests",
@@ -3244,13 +3244,11 @@
         "../browser/chromeos/policy/blocking_login_browsertest.cc",
         "../browser/chromeos/policy/browser_policy_connector_chromeos_browsertest.cc",
         "../browser/chromeos/policy/component_active_directory_policy_browsertest.cc",
-        "../browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc",
         "../browser/chromeos/policy/device_cloud_policy_browsertest.cc",
         "../browser/chromeos/policy/device_display_cros_browser_test.cc",
         "../browser/chromeos/policy/device_display_cros_browser_test.h",
         "../browser/chromeos/policy/device_local_account_browsertest.cc",
         "../browser/chromeos/policy/device_login_screen_policy_browsertest.cc",
-        "../browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc",
         "../browser/chromeos/policy/device_policy_cros_browser_test.cc",
         "../browser/chromeos/policy/device_policy_cros_browser_test.h",
         "../browser/chromeos/policy/device_quirks_policy_browsertest.cc",
@@ -3270,7 +3268,10 @@
         "../browser/chromeos/policy/dlp/mock_dlp_content_manager.h",
         "../browser/chromeos/policy/dlp/mock_dlp_rules_manager.cc",
         "../browser/chromeos/policy/dlp/mock_dlp_rules_manager.h",
-        "../browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc",
+        "../browser/chromeos/policy/external_data/device_cloud_external_data_policy_observer_browsertest.cc",
+        "../browser/chromeos/policy/external_data/device_policy_cloud_external_data_manager_browsertest.cc",
+        "../browser/chromeos/policy/external_data/handlers/device_wilco_dtc_configuration_external_data_handler_browsertest.cc",
+        "../browser/chromeos/policy/external_data/user_cloud_external_data_manager_browsertest.cc",
         "../browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc",
         "../browser/chromeos/policy/login_policy_test_base.cc",
         "../browser/chromeos/policy/login_policy_test_base.h",
@@ -3289,7 +3290,6 @@
         "../browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc",
         "../browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc",
         "../browser/chromeos/policy/user_affiliation_browsertest.cc",
-        "../browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc",
         "../browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc",
         "../browser/chromeos/policy/variations_service_policy_browsertest.cc",
         "../browser/chromeos/preferences_chromeos_browsertest.cc",
@@ -3474,7 +3474,7 @@
       ]
 
       deps += [
-        "//ash/content/help_app_ui/search:mojo_bindings",
+        "//chromeos/components/help_app_ui/search:mojo_bindings",
         "//chromeos/components/media_app_ui:buildflags",
         "//chromeos/ui/frame:test_support",
         "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
diff --git a/chrome/test/base/ui_test_utils.h b/chrome/test/base/ui_test_utils.h
index e948c0e..bb61076 100644
--- a/chrome/test/base/ui_test_utils.h
+++ b/chrome/test/base/ui_test_utils.h
@@ -11,7 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/scoped_observer.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
diff --git a/chrome/test/data/webui/print_preview/header_test.js b/chrome/test/data/webui/print_preview/header_test.js
index 5b9cf47..6c1ccca9 100644
--- a/chrome/test/data/webui/print_preview/header_test.js
+++ b/chrome/test/data/webui/print_preview/header_test.js
@@ -31,7 +31,7 @@
     document.body.innerHTML = '';
 
     pluralString = new TestPluralStringProxy();
-    PrintPreviewPluralStringProxyImpl.setInstance(pluralString);
+    PrintPreviewPluralStringProxyImpl.instance_ = pluralString;
     pluralString.text = '1 sheet of paper';
 
     const model = /** @type {!PrintPreviewModelElement} */ (
diff --git a/chrome/test/data/webui/print_preview/policy_test.js b/chrome/test/data/webui/print_preview/policy_test.js
index e246961d..36b9110 100644
--- a/chrome/test/data/webui/print_preview/policy_test.js
+++ b/chrome/test/data/webui/print_preview/policy_test.js
@@ -275,7 +275,7 @@
 
   test(assert(policy_tests.TestNames.SheetsPolicy), async () => {
     const pluralString = new PolicyTestPluralStringProxy();
-    PrintPreviewPluralStringProxyImpl.setInstance(pluralString);
+    PrintPreviewPluralStringProxyImpl.instance_ = pluralString;
     pluralString.text = 'Exceeds limit of 1 sheet of paper';
 
     const tests = [
diff --git a/chrome/test/data/webui/settings/autofill_page_test.js b/chrome/test/data/webui/settings/autofill_page_test.js
index fba8145..7c8b740 100644
--- a/chrome/test/data/webui/settings/autofill_page_test.js
+++ b/chrome/test/data/webui/settings/autofill_page_test.js
@@ -307,7 +307,7 @@
     passwordManager = new TestPasswordManagerProxy();
     PasswordManagerImpl.instance_ = passwordManager;
     pluralString = new TestPluralStringProxy();
-    SettingsPluralStringProxyImpl.setInstance(pluralString);
+    SettingsPluralStringProxyImpl.instance_ = pluralString;
 
     autofillPage = createAutofillPageSection();
   });
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index 8bf0adb..72e5b13 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -320,7 +320,7 @@
     // Override the PasswordManagerImpl for testing.
     passwordManager = new TestPasswordManagerProxy();
     pluralString = new TestPluralStringProxy();
-    SettingsPluralStringProxyImpl.setInstance(pluralString);
+    SettingsPluralStringProxyImpl.instance_ = pluralString;
 
     PasswordManagerImpl.instance_ = passwordManager;
     elementFactory = new PasswordSectionElementFactory(document);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index f0f4501a..77d8bdf2 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14007.0.0
\ No newline at end of file
+14008.0.0
\ No newline at end of file
diff --git a/chromeos/components/BUILD.gn b/chromeos/components/BUILD.gn
index 114ea1fe..83f37c5 100644
--- a/chromeos/components/BUILD.gn
+++ b/chromeos/components/BUILD.gn
@@ -28,6 +28,7 @@
     "//chromeos/components/drivefs:unit_tests",
     "//chromeos/components/eche_app_ui:unit_tests",
     "//chromeos/components/feature_usage:unit_tests",
+    "//chromeos/components/help_app_ui:unit_tests",
     "//chromeos/components/local_search_service:unit_tests",
     "//chromeos/components/local_search_service/public/mojom:unit_tests",
     "//chromeos/components/mojo_bootstrap:unit_tests",
@@ -73,6 +74,7 @@
     "//chromeos/components/connectivity_diagnostics:closure_compile",
     "//chromeos/components/diagnostics_ui:closure_compile",
     "//chromeos/components/eche_app_ui:closure_compile",
+    "//chromeos/components/help_app_ui:closure_compile",
     "//chromeos/components/media_app_ui:closure_compile",
     "//chromeos/components/multidevice/debug_webui/resources:closure_compile",
     "//chromeos/components/personalization_app:closure_compile",
diff --git a/chromeos/components/camera_app_ui/resources/js/intent.js b/chromeos/components/camera_app_ui/resources/js/intent.js
index b640201..046c92b7 100644
--- a/chromeos/components/camera_app_ui/resources/js/intent.js
+++ b/chromeos/components/camera_app_ui/resources/js/intent.js
@@ -113,22 +113,6 @@
   }
 
   /**
-   * Notifies ARC++ to cancel the intent.
-   * @return {!Promise}
-   */
-  async cancel() {
-    if (this.done) {
-      return;
-    }
-    this.done_ = true;
-    // TODO(crbug.com/1125997): We send the metrics before the actual action
-    // here to workaround the issue that codes behind "await" might not be
-    // executed when unloading window.
-    this.logResult(metrics.IntentResultType.CANCELED);
-    await this.chromeHelper_.cancel(this.intentId);
-  }
-
-  /**
    * Notifies ARC++ to append data to the intent result.
    * @param {!Uint8Array} data The data to be appended to intent result.
    * @return {!Promise}
diff --git a/chromeos/components/camera_app_ui/resources/js/mojo/chrome_helper.js b/chromeos/components/camera_app_ui/resources/js/mojo/chrome_helper.js
index 2212e4b..dd89861 100644
--- a/chromeos/components/camera_app_ui/resources/js/mojo/chrome_helper.js
+++ b/chromeos/components/camera_app_ui/resources/js/mojo/chrome_helper.js
@@ -183,17 +183,6 @@
   }
 
   /**
-   * Notifies ARC++ to cancel the intent.
-   * @param {number} intentId Intent id of the intent to be canceled.
-   * @return {!Promise}
-   */
-  async cancel(intentId) {
-    const ret = this.remote_.handleCameraResult(
-        intentId, arc.mojom.CameraIntentAction.CANCEL, []);
-    await this.checkReturn_('cancel()', ret);
-  }
-
-  /**
    * Forces casting type from Uint8Array to !Array<number>.
    * @param {!Uint8Array} data
    * @return {!Array<number>}
diff --git a/ash/content/help_app_ui/BUILD.gn b/chromeos/components/help_app_ui/BUILD.gn
similarity index 88%
rename from ash/content/help_app_ui/BUILD.gn
rename to chromeos/components/help_app_ui/BUILD.gn
index 64eea4e..7ac0482 100644
--- a/ash/content/help_app_ui/BUILD.gn
+++ b/chromeos/components/help_app_ui/BUILD.gn
@@ -35,16 +35,16 @@
   deps = [
     ":mojo_bindings",
     ":mojo_bindings_js",
-    "//ash/components/resources:help_app_bundle_resources",
-    "//ash/components/resources:help_app_kids_magazine_bundle_resources",
-    "//ash/components/resources:help_app_resources",
     "//ash/constants",
-    "//ash/content/help_app_ui/search:mojo_bindings",
-    "//ash/content/help_app_ui/search:mojo_bindings_js",
+    "//chromeos/components/help_app_ui/search:mojo_bindings",
+    "//chromeos/components/help_app_ui/search:mojo_bindings_js",
     "//chromeos/components/local_search_service/public/cpp",
     "//chromeos/components/local_search_service/public/mojom",
     "//chromeos/components/local_search_service/public/mojom:mojom_js",
     "//chromeos/components/web_applications",
+    "//chromeos/resources:help_app_bundle_resources",
+    "//chromeos/resources:help_app_kids_magazine_bundle_resources",
+    "//chromeos/resources:help_app_resources",
     "//chromeos/strings",
     "//chromeos/system",
     "//components/keyed_service/content:content",
@@ -72,8 +72,8 @@
 
   deps = [
     ":help_app_ui",
-    "//ash/content/help_app_ui/search:mojo_bindings",
     "//base/test:test_support",
+    "//chromeos/components/help_app_ui/search:mojo_bindings",
     "//chromeos/components/local_search_service/public/mojom:mojom",
     "//mojo/public/cpp/bindings:bindings",
     "//testing/gtest",
@@ -157,7 +157,7 @@
   sources = [ "test/guest_query_receiver.js" ]
   deps = [
     ":test_driver_api_js",
-    "//ash/content/help_app_ui/resources:receiver",
+    "//chromeos/components/help_app_ui/resources:receiver",
     "//chromeos/components/system_apps/public/js:message_pipe",
   ]
 }
@@ -168,7 +168,7 @@
   externs_list = [ "//third_party/chaijs/externs/chai-3.5.js" ]
   deps = [
     ":test_driver_api_js",
-    "//ash/content/help_app_ui/resources:browser_proxy",
+    "//chromeos/components/help_app_ui/resources:browser_proxy",
     "//chromeos/components/system_apps/public/js:message_pipe",
   ]
 }
@@ -180,7 +180,7 @@
       [ "//chromeos/components/web_applications/js2gtest_support.externs.js" ]
   deps = [
     ":test_driver_js",
-    "//ash/content/help_app_ui/resources:browser_proxy",
+    "//chromeos/components/help_app_ui/resources:browser_proxy",
     "//chromeos/components/system_apps/public/js:message_pipe",
   ]
 }
@@ -192,7 +192,7 @@
       [ "//chromeos/components/web_applications/js2gtest_support.externs.js" ]
   deps = [
     ":test_driver_js",
-    "//ash/content/help_app_ui/resources:receiver",
+    "//chromeos/components/help_app_ui/resources:receiver",
     "//chromeos/components/system_apps/public/js:message_pipe",
   ]
 }
diff --git a/ash/content/help_app_ui/DEPS b/chromeos/components/help_app_ui/DEPS
similarity index 72%
rename from ash/content/help_app_ui/DEPS
rename to chromeos/components/help_app_ui/DEPS
index a67fb025..fdc3d32 100644
--- a/ash/content/help_app_ui/DEPS
+++ b/chromeos/components/help_app_ui/DEPS
@@ -1,9 +1,7 @@
 include_rules = [
   # Do not add chrome here (use a delegate instead).
-  "+ash/grit/ash_help_app_resources.h",
-  # TODO(https://crbug.com/1164001): remove when local_search_service is moved.
-  "+chromeos/components/local_search_service",
   "+chromeos/components/web_applications",
+  "+chromeos/grit/chromeos_help_app_resources.h",
   "+chromeos/strings/grit/chromeos_strings.h",
   "+components/content_settings/core/common",
   "+components/keyed_service/content",
diff --git a/ash/content/help_app_ui/DIR_METADATA b/chromeos/components/help_app_ui/DIR_METADATA
similarity index 100%
rename from ash/content/help_app_ui/DIR_METADATA
rename to chromeos/components/help_app_ui/DIR_METADATA
diff --git a/ash/content/help_app_ui/OWNERS b/chromeos/components/help_app_ui/OWNERS
similarity index 100%
rename from ash/content/help_app_ui/OWNERS
rename to chromeos/components/help_app_ui/OWNERS
diff --git a/ash/content/help_app_ui/README b/chromeos/components/help_app_ui/README
similarity index 100%
rename from ash/content/help_app_ui/README
rename to chromeos/components/help_app_ui/README
diff --git a/ash/content/help_app_ui/help_app_manager.cc b/chromeos/components/help_app_ui/help_app_manager.cc
similarity index 83%
rename from ash/content/help_app_ui/help_app_manager.cc
rename to chromeos/components/help_app_ui/help_app_manager.cc
index 19fd40d..37aa901 100644
--- a/ash/content/help_app_ui/help_app_manager.cc
+++ b/chromeos/components/help_app_ui/help_app_manager.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 "ash/content/help_app_ui/help_app_manager.h"
+#include "chromeos/components/help_app_ui/help_app_manager.h"
 
-#include "ash/content/help_app_ui/search/search_handler.h"
-#include "ash/content/help_app_ui/search/search_tag_registry.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
+#include "chromeos/components/help_app_ui/search/search_tag_registry.h"
 #include "content/public/browser/web_ui_data_source.h"
 
 namespace chromeos {
diff --git a/ash/content/help_app_ui/help_app_manager.h b/chromeos/components/help_app_ui/help_app_manager.h
similarity index 88%
rename from ash/content/help_app_ui/help_app_manager.h
rename to chromeos/components/help_app_ui/help_app_manager.h
index db05e16..b2f754f 100644
--- a/ash/content/help_app_ui/help_app_manager.h
+++ b/chromeos/components/help_app_ui/help_app_manager.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_CONTENT_HELP_APP_UI_HELP_APP_MANAGER_H_
-#define ASH_CONTENT_HELP_APP_UI_HELP_APP_MANAGER_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_MANAGER_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_MANAGER_H_
 
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -51,4 +51,4 @@
 }  // namespace help_app
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_HELP_APP_MANAGER_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_MANAGER_H_
diff --git a/ash/content/help_app_ui/help_app_manager_factory.cc b/chromeos/components/help_app_ui/help_app_manager_factory.cc
similarity index 92%
rename from ash/content/help_app_ui/help_app_manager_factory.cc
rename to chromeos/components/help_app_ui/help_app_manager_factory.cc
index f6f2f5a..774741e 100644
--- a/ash/content/help_app_ui/help_app_manager_factory.cc
+++ b/chromeos/components/help_app_ui/help_app_manager_factory.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/content/help_app_ui/help_app_manager_factory.h"
-#include "ash/content/help_app_ui/help_app_manager.h"
+#include "chromeos/components/help_app_ui/help_app_manager_factory.h"
+#include "chromeos/components/help_app_ui/help_app_manager.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 
diff --git a/ash/content/help_app_ui/help_app_manager_factory.h b/chromeos/components/help_app_ui/help_app_manager_factory.h
similarity index 85%
rename from ash/content/help_app_ui/help_app_manager_factory.h
rename to chromeos/components/help_app_ui/help_app_manager_factory.h
index a46426e..b6fba85 100644
--- a/ash/content/help_app_ui/help_app_manager_factory.h
+++ b/chromeos/components/help_app_ui/help_app_manager_factory.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_CONTENT_HELP_APP_UI_HELP_APP_MANAGER_FACTORY_H_
-#define ASH_CONTENT_HELP_APP_UI_HELP_APP_MANAGER_FACTORY_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_MANAGER_FACTORY_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_MANAGER_FACTORY_H_
 
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
@@ -38,4 +38,4 @@
 }  // namespace help_app
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_HELP_APP_MANAGER_FACTORY_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_MANAGER_FACTORY_H_
diff --git a/ash/content/help_app_ui/help_app_page_handler.cc b/chromeos/components/help_app_ui/help_app_page_handler.cc
similarity index 89%
rename from ash/content/help_app_ui/help_app_page_handler.cc
rename to chromeos/components/help_app_ui/help_app_page_handler.cc
index e372ca8..dad83215 100644
--- a/ash/content/help_app_ui/help_app_page_handler.cc
+++ b/chromeos/components/help_app_ui/help_app_page_handler.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/content/help_app_ui/help_app_page_handler.h"
+#include "chromeos/components/help_app_ui/help_app_page_handler.h"
 
 #include <utility>
 
 #include "ash/constants/ash_features.h"
-#include "ash/content/help_app_ui/help_app_ui.h"
-#include "ash/content/help_app_ui/help_app_ui_delegate.h"
 #include "base/feature_list.h"
+#include "chromeos/components/help_app_ui/help_app_ui.h"
+#include "chromeos/components/help_app_ui/help_app_ui_delegate.h"
 
 HelpAppPageHandler::HelpAppPageHandler(
     chromeos::HelpAppUI* help_app_ui,
diff --git a/ash/content/help_app_ui/help_app_page_handler.h b/chromeos/components/help_app_ui/help_app_page_handler.h
similarity index 83%
rename from ash/content/help_app_ui/help_app_page_handler.h
rename to chromeos/components/help_app_ui/help_app_page_handler.h
index dc081b96..879af1a 100644
--- a/ash/content/help_app_ui/help_app_page_handler.h
+++ b/chromeos/components/help_app_ui/help_app_page_handler.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_CONTENT_HELP_APP_UI_HELP_APP_PAGE_HANDLER_H_
-#define ASH_CONTENT_HELP_APP_UI_HELP_APP_PAGE_HANDLER_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_PAGE_HANDLER_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_PAGE_HANDLER_H_
 
-#include "ash/content/help_app_ui/help_app_ui.mojom.h"
+#include "chromeos/components/help_app_ui/help_app_ui.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -40,4 +40,4 @@
   bool is_launcher_search_enabled_;
 };
 
-#endif  // ASH_CONTENT_HELP_APP_UI_HELP_APP_PAGE_HANDLER_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_PAGE_HANDLER_H_
diff --git a/ash/content/help_app_ui/help_app_ui.cc b/chromeos/components/help_app_ui/help_app_ui.cc
similarity index 92%
rename from ash/content/help_app_ui/help_app_ui.cc
rename to chromeos/components/help_app_ui/help_app_ui.cc
index e9ead8d1..6f655630 100644
--- a/ash/content/help_app_ui/help_app_ui.cc
+++ b/chromeos/components/help_app_ui/help_app_ui.cc
@@ -2,21 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/content/help_app_ui/help_app_ui.h"
+#include "chromeos/components/help_app_ui/help_app_ui.h"
 
 #include <utility>
 
 #include "ash/constants/ash_features.h"
-#include "ash/content/help_app_ui/help_app_manager.h"
-#include "ash/content/help_app_ui/help_app_manager_factory.h"
-#include "ash/content/help_app_ui/help_app_page_handler.h"
-#include "ash/content/help_app_ui/help_app_untrusted_ui.h"
-#include "ash/content/help_app_ui/search/search_handler.h"
-#include "ash/content/help_app_ui/url_constants.h"
-#include "ash/grit/ash_help_app_resources.h"
+#include "chromeos/components/help_app_ui/help_app_manager.h"
+#include "chromeos/components/help_app_ui/help_app_manager_factory.h"
+#include "chromeos/components/help_app_ui/help_app_page_handler.h"
+#include "chromeos/components/help_app_ui/help_app_untrusted_ui.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy_factory.h"
 #include "chromeos/components/local_search_service/public/mojom/types.mojom.h"
+#include "chromeos/grit/chromeos_help_app_resources.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/browser/web_contents.h"
diff --git a/ash/content/help_app_ui/help_app_ui.gni b/chromeos/components/help_app_ui/help_app_ui.gni
similarity index 100%
rename from ash/content/help_app_ui/help_app_ui.gni
rename to chromeos/components/help_app_ui/help_app_ui.gni
diff --git a/ash/content/help_app_ui/help_app_ui.h b/chromeos/components/help_app_ui/help_app_ui.h
similarity index 82%
rename from ash/content/help_app_ui/help_app_ui.h
rename to chromeos/components/help_app_ui/help_app_ui.h
index d3da00c..9ecfc1e 100644
--- a/ash/content/help_app_ui/help_app_ui.h
+++ b/chromeos/components/help_app_ui/help_app_ui.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 ASH_CONTENT_HELP_APP_UI_HELP_APP_UI_H_
-#define ASH_CONTENT_HELP_APP_UI_HELP_APP_UI_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UI_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UI_H_
 
 #include <memory>
 
-#include "ash/content/help_app_ui/help_app_ui.mojom.h"
-#include "ash/content/help_app_ui/help_app_ui_delegate.h"
-#include "ash/content/help_app_ui/search/search.mojom.h"
+#include "chromeos/components/help_app_ui/help_app_ui.mojom.h"
+#include "chromeos/components/help_app_ui/help_app_ui_delegate.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
 #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
@@ -58,4 +58,4 @@
 
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_HELP_APP_UI_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UI_H_
diff --git a/ash/content/help_app_ui/help_app_ui.mojom b/chromeos/components/help_app_ui/help_app_ui.mojom
similarity index 100%
rename from ash/content/help_app_ui/help_app_ui.mojom
rename to chromeos/components/help_app_ui/help_app_ui.mojom
diff --git a/ash/content/help_app_ui/help_app_ui_delegate.h b/chromeos/components/help_app_ui/help_app_ui_delegate.h
similarity index 86%
rename from ash/content/help_app_ui/help_app_ui_delegate.h
rename to chromeos/components/help_app_ui/help_app_ui_delegate.h
index 234c56ce..0c183ed 100644
--- a/ash/content/help_app_ui/help_app_ui_delegate.h
+++ b/chromeos/components/help_app_ui/help_app_ui_delegate.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_CONTENT_HELP_APP_UI_HELP_APP_UI_DELEGATE_H_
-#define ASH_CONTENT_HELP_APP_UI_HELP_APP_UI_DELEGATE_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UI_DELEGATE_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UI_DELEGATE_H_
 
 #include <string>
 
@@ -41,4 +41,4 @@
   virtual void MaybeShowDiscoverNotification() = 0;
 };
 
-#endif  // ASH_CONTENT_HELP_APP_UI_HELP_APP_UI_DELEGATE_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UI_DELEGATE_H_
diff --git a/ash/content/help_app_ui/help_app_untrusted_ui.cc b/chromeos/components/help_app_ui/help_app_untrusted_ui.cc
similarity index 77%
rename from ash/content/help_app_ui/help_app_untrusted_ui.cc
rename to chromeos/components/help_app_ui/help_app_untrusted_ui.cc
index 0dd040ae..58561bd 100644
--- a/ash/content/help_app_ui/help_app_untrusted_ui.cc
+++ b/chromeos/components/help_app_ui/help_app_untrusted_ui.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/content/help_app_ui/help_app_untrusted_ui.h"
+#include "chromeos/components/help_app_ui/help_app_untrusted_ui.h"
 
-#include "ash/content/help_app_ui/help_app_ui_delegate.h"
-#include "ash/content/help_app_ui/url_constants.h"
-#include "ash/grit/ash_help_app_bundle_resources.h"
-#include "ash/grit/ash_help_app_bundle_resources_map.h"
-#include "ash/grit/ash_help_app_kids_magazine_bundle_resources.h"
-#include "ash/grit/ash_help_app_kids_magazine_bundle_resources_map.h"
-#include "ash/grit/ash_help_app_resources.h"
 #include "base/strings/string_piece.h"
+#include "chromeos/components/help_app_ui/help_app_ui_delegate.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
+#include "chromeos/grit/chromeos_help_app_bundle_resources.h"
+#include "chromeos/grit/chromeos_help_app_bundle_resources_map.h"
+#include "chromeos/grit/chromeos_help_app_kids_magazine_bundle_resources.h"
+#include "chromeos/grit/chromeos_help_app_kids_magazine_bundle_resources_map.h"
+#include "chromeos/grit/chromeos_help_app_resources.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
@@ -46,9 +46,9 @@
                           IDR_HELP_APP_APP_SCRIPTS_JS);
   source->DisableTrustedTypesCSP();
 
-  // Add all resources from ash_help_app_bundle.pak.
-  source->AddResourcePaths(base::make_span(kAshHelpAppBundleResources,
-                                           kAshHelpAppBundleResourcesSize));
+  // Add all resources from chromeos_help_app_bundle.pak.
+  source->AddResourcePaths(base::make_span(
+      kChromeosHelpAppBundleResources, kChromeosHelpAppBundleResourcesSize));
 
   // Add device and feature flags.
   delegate->PopulateLoadTimeData(source);
@@ -76,11 +76,11 @@
   // While the JS and CSS file are stored in /kids_magazine/static/..., the HTML
   // file references /static/... directly. We need to strip the "kids_magazine"
   // prefix from the path.
-  for (size_t i = 0; i < kAshHelpAppKidsMagazineBundleResourcesSize; i++) {
+  for (size_t i = 0; i < kChromeosHelpAppKidsMagazineBundleResourcesSize; i++) {
     source->AddResourcePath(
-        StripPrefix(kAshHelpAppKidsMagazineBundleResources[i].path,
+        StripPrefix(kChromeosHelpAppKidsMagazineBundleResources[i].path,
                     "kids_magazine/"),
-        kAshHelpAppKidsMagazineBundleResources[i].id);
+        kChromeosHelpAppKidsMagazineBundleResources[i].id);
   }
 
   // Add chrome://help-app and chrome-untrusted://help-app as frame ancestors.
diff --git a/ash/content/help_app_ui/help_app_untrusted_ui.h b/chromeos/components/help_app_ui/help_app_untrusted_ui.h
similarity index 74%
rename from ash/content/help_app_ui/help_app_untrusted_ui.h
rename to chromeos/components/help_app_ui/help_app_untrusted_ui.h
index fbd9d44..3461361 100644
--- a/ash/content/help_app_ui/help_app_untrusted_ui.h
+++ b/chromeos/components/help_app_ui/help_app_untrusted_ui.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_CONTENT_HELP_APP_UI_HELP_APP_UNTRUSTED_UI_H_
-#define ASH_CONTENT_HELP_APP_UI_HELP_APP_UNTRUSTED_UI_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UNTRUSTED_UI_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UNTRUSTED_UI_H_
 
 namespace content {
 class WebUIDataSource;
@@ -20,4 +20,4 @@
 content::WebUIDataSource* CreateHelpAppKidsMagazineUntrustedDataSource();
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_HELP_APP_UNTRUSTED_UI_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_HELP_APP_UNTRUSTED_UI_H_
diff --git a/ash/content/help_app_ui/resources/BUILD.gn b/chromeos/components/help_app_ui/resources/BUILD.gn
similarity index 88%
rename from ash/content/help_app_ui/resources/BUILD.gn
rename to chromeos/components/help_app_ui/resources/BUILD.gn
index 1d1fa6b..3a3ac48 100644
--- a/ash/content/help_app_ui/resources/BUILD.gn
+++ b/chromeos/components/help_app_ui/resources/BUILD.gn
@@ -33,8 +33,8 @@
   ]
   deps = [
     ":message_types",
-    "//ash/content/help_app_ui:mojo_bindings_js_library_for_compile",
-    "//ash/content/help_app_ui/search:mojo_bindings_js_library_for_compile",
+    "//chromeos/components/help_app_ui:mojo_bindings_js_library_for_compile",
+    "//chromeos/components/help_app_ui/search:mojo_bindings_js_library_for_compile",
     "//chromeos/components/local_search_service/public/mojom:mojom_js_library_for_compile",
     "//chromeos/components/system_apps/public/js:message_pipe",
   ]
diff --git a/ash/content/help_app_ui/resources/app.html b/chromeos/components/help_app_ui/resources/app.html
similarity index 100%
rename from ash/content/help_app_ui/resources/app.html
rename to chromeos/components/help_app_ui/resources/app.html
diff --git a/ash/content/help_app_ui/resources/app_icon_192.png b/chromeos/components/help_app_ui/resources/app_icon_192.png
similarity index 100%
rename from ash/content/help_app_ui/resources/app_icon_192.png
rename to chromeos/components/help_app_ui/resources/app_icon_192.png
Binary files differ
diff --git a/ash/content/help_app_ui/resources/app_icon_512.png b/chromeos/components/help_app_ui/resources/app_icon_512.png
similarity index 100%
rename from ash/content/help_app_ui/resources/app_icon_512.png
rename to chromeos/components/help_app_ui/resources/app_icon_512.png
Binary files differ
diff --git a/ash/content/help_app_ui/resources/browser_proxy.js b/chromeos/components/help_app_ui/resources/browser_proxy.js
similarity index 100%
rename from ash/content/help_app_ui/resources/browser_proxy.js
rename to chromeos/components/help_app_ui/resources/browser_proxy.js
diff --git a/ash/content/help_app_ui/resources/help_app.externs.js b/chromeos/components/help_app_ui/resources/help_app.externs.js
similarity index 100%
rename from ash/content/help_app_ui/resources/help_app.externs.js
rename to chromeos/components/help_app_ui/resources/help_app.externs.js
diff --git a/ash/content/help_app_ui/resources/help_app_app_scripts.js b/chromeos/components/help_app_ui/resources/help_app_app_scripts.js
similarity index 77%
rename from ash/content/help_app_ui/resources/help_app_app_scripts.js
rename to chromeos/components/help_app_ui/resources/help_app_app_scripts.js
index df6d040..9375725 100644
--- a/ash/content/help_app_ui/resources/help_app_app_scripts.js
+++ b/chromeos/components/help_app_ui/resources/help_app_app_scripts.js
@@ -4,6 +4,6 @@
 
 /** @fileoverview Concatenation of the JS files we use in app.html. */
 
-// <include src="../../../../chromeos/components/system_apps/public/js/message_pipe.js">
+// <include src="../../system_apps/public/js/message_pipe.js">
 // <include src="message_types.js">
 // <include src="receiver.js">
diff --git a/ash/content/help_app_ui/resources/help_app_index_scripts.js b/chromeos/components/help_app_ui/resources/help_app_index_scripts.js
similarity index 77%
rename from ash/content/help_app_ui/resources/help_app_index_scripts.js
rename to chromeos/components/help_app_ui/resources/help_app_index_scripts.js
index 0e57c06..b20808c 100644
--- a/ash/content/help_app_ui/resources/help_app_index_scripts.js
+++ b/chromeos/components/help_app_ui/resources/help_app_index_scripts.js
@@ -4,6 +4,6 @@
 
 /** @fileoverview Concatenation of the JS files we use in index.html. */
 
-// <include src="../../../../chromeos/components/system_apps/public/js/message_pipe.js">
+// <include src="../../system_apps/public/js/message_pipe.js">
 // <include src="message_types.js">
 // <include src="browser_proxy.js">
diff --git a/ash/content/help_app_ui/resources/help_app_resources.grd b/chromeos/components/help_app_ui/resources/help_app_resources.grd
similarity index 79%
rename from ash/content/help_app_ui/resources/help_app_resources.grd
rename to chromeos/components/help_app_ui/resources/help_app_resources.grd
index de10b9a..aa91e6ff 100644
--- a/ash/content/help_app_ui/resources/help_app_resources.grd
+++ b/chromeos/components/help_app_ui/resources/help_app_resources.grd
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
   <outputs>
-    <output filename="grit/ash_help_app_resources.h" type="rc_header">
+    <output filename="grit/chromeos_help_app_resources.h" type="rc_header">
       <emit emit_type="prepend"></emit>
     </output>
-    <output filename="grit/ash_help_app_resources_map.cc"
+    <output filename="grit/chromeos_help_app_resources_map.cc"
         type="resource_file_map_source" />
-    <output filename="grit/ash_help_app_resources_map.h"
+    <output filename="grit/chromeos_help_app_resources_map.h"
         type="resource_map_header" />
-    <output filename="ash_help_app_resources.pak" type="data_package" />
+    <output filename="chromeos_help_app_resources.pak" type="data_package" />
   </outputs>
 
   <release seq="1">
@@ -20,7 +20,7 @@
       <include name="IDR_HELP_APP_ICON_512" file="app_icon_512.png"
           type="BINDATA" />
       <include name="IDR_HELP_APP_HELP_APP_MOJOM_JS"
-          file="${root_gen_dir}/ash/content/help_app_ui/help_app_ui.mojom-lite.js"
+          file="${root_gen_dir}/chromeos/components/help_app_ui/help_app_ui.mojom-lite.js"
           resource_path="help_app_ui.mojom-lite.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_HELP_APP_LOCAL_SEARCH_SERVICE_TYPES_MOJOM_JS"
           file="${root_gen_dir}/chromeos/components/local_search_service/public/mojom/types.mojom-lite.js"
@@ -29,7 +29,7 @@
           file="${root_gen_dir}/chromeos/components/local_search_service/public/mojom/index.mojom-lite.js"
           resource_path="local_search_service_index.mojom-lite.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_HELP_APP_SEARCH_MOJOM_JS"
-          file="${root_gen_dir}/ash/content/help_app_ui/search/search.mojom-lite.js"
+          file="${root_gen_dir}/chromeos/components/help_app_ui/search/search.mojom-lite.js"
           resource_path="help_app_search.mojom-lite.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_HELP_APP_INDEX_SCRIPTS_JS" file="help_app_index_scripts.js" flattenhtml="true" type="BINDATA" />
 
diff --git a/ash/content/help_app_ui/resources/index.html b/chromeos/components/help_app_ui/resources/index.html
similarity index 100%
rename from ash/content/help_app_ui/resources/index.html
rename to chromeos/components/help_app_ui/resources/index.html
diff --git a/ash/content/help_app_ui/resources/message_types.js b/chromeos/components/help_app_ui/resources/message_types.js
similarity index 100%
rename from ash/content/help_app_ui/resources/message_types.js
rename to chromeos/components/help_app_ui/resources/message_types.js
diff --git a/ash/content/help_app_ui/resources/mock/BUILD.gn b/chromeos/components/help_app_ui/resources/mock/BUILD.gn
similarity index 83%
rename from ash/content/help_app_ui/resources/mock/BUILD.gn
rename to chromeos/components/help_app_ui/resources/mock/BUILD.gn
index 64f1166..95da3c5 100644
--- a/ash/content/help_app_ui/resources/mock/BUILD.gn
+++ b/chromeos/components/help_app_ui/resources/mock/BUILD.gn
@@ -13,5 +13,6 @@
 }
 
 js_library("app_bin") {
-  externs_list = [ "//ash/content/help_app_ui/resources/help_app.externs.js" ]
+  externs_list =
+      [ "//chromeos/components/help_app_ui/resources/help_app.externs.js" ]
 }
diff --git a/ash/content/help_app_ui/resources/mock/app_bin.js b/chromeos/components/help_app_ui/resources/mock/app_bin.js
similarity index 100%
rename from ash/content/help_app_ui/resources/mock/app_bin.js
rename to chromeos/components/help_app_ui/resources/mock/app_bin.js
diff --git a/chromeos/components/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd b/chromeos/components/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
new file mode 100644
index 0000000..439b5cb
--- /dev/null
+++ b/chromeos/components/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit current_release="1" latest_public_release="0" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/chromeos_help_app_bundle_resources.h" type="rc_header">
+      <emit emit_type="prepend"/>
+    </output>
+    <output filename="grit/chromeos_help_app_bundle_resources_map.cc" type="resource_file_map_source"/>
+    <output filename="grit/chromeos_help_app_bundle_resources_map.h" type="resource_map_header"/>
+    <output filename="chromeos_help_app_bundle_resources.pak" type="data_package"/>
+  </outputs>
+  <release seq="1">
+    <includes>
+      <include name="IDR_HELP_APP_APP_BIN_JS" file="app_bin.js" type="BINDATA" />
+    </includes>
+  </release>
+</grit>
diff --git a/chromeos/components/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd b/chromeos/components/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd
new file mode 100644
index 0000000..6d076a1
--- /dev/null
+++ b/chromeos/components/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit current_release="1" latest_public_release="0" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/chromeos_help_app_kids_magazine_bundle_resources.h" type="rc_header">
+      <emit emit_type="prepend"/>
+    </output>
+    <output filename="grit/chromeos_help_app_kids_magazine_bundle_resources_map.cc" type="resource_file_map_source"/>
+    <output filename="grit/chromeos_help_app_kids_magazine_bundle_resources_map.h" type="resource_map_header"/>
+    <output filename="chromeos_help_app_kids_magazine_bundle_resources.pak" type="data_package"/>
+  </outputs>
+  <release seq="1">
+    <includes>
+      <include name="IDR_HELP_APP_KIDS_MAGAZINE_INDEX_HTML" file="index.html" type="BINDATA" />
+    </includes>
+  </release>
+</grit>
diff --git a/ash/content/help_app_ui/resources/mock/index.html b/chromeos/components/help_app_ui/resources/mock/index.html
similarity index 100%
rename from ash/content/help_app_ui/resources/mock/index.html
rename to chromeos/components/help_app_ui/resources/mock/index.html
diff --git a/ash/content/help_app_ui/resources/receiver.js b/chromeos/components/help_app_ui/resources/receiver.js
similarity index 100%
rename from ash/content/help_app_ui/resources/receiver.js
rename to chromeos/components/help_app_ui/resources/receiver.js
diff --git a/ash/content/help_app_ui/search/BUILD.gn b/chromeos/components/help_app_ui/search/BUILD.gn
similarity index 100%
rename from ash/content/help_app_ui/search/BUILD.gn
rename to chromeos/components/help_app_ui/search/BUILD.gn
diff --git a/ash/content/help_app_ui/search/OWNERS b/chromeos/components/help_app_ui/search/OWNERS
similarity index 100%
rename from ash/content/help_app_ui/search/OWNERS
rename to chromeos/components/help_app_ui/search/OWNERS
diff --git a/ash/content/help_app_ui/search/search.mojom b/chromeos/components/help_app_ui/search/search.mojom
similarity index 100%
rename from ash/content/help_app_ui/search/search.mojom
rename to chromeos/components/help_app_ui/search/search.mojom
diff --git a/ash/content/help_app_ui/search/search_handler.cc b/chromeos/components/help_app_ui/search/search_handler.cc
similarity index 98%
rename from ash/content/help_app_ui/search/search_handler.cc
rename to chromeos/components/help_app_ui/search/search_handler.cc
index 7a20c93f..37dbd9f7 100644
--- a/ash/content/help_app_ui/search/search_handler.cc
+++ b/chromeos/components/help_app_ui/search/search_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 "ash/content/help_app_ui/search/search_handler.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
 
 #include <algorithm>
 #include <utility>
diff --git a/ash/content/help_app_ui/search/search_handler.h b/chromeos/components/help_app_ui/search/search_handler.h
similarity index 90%
rename from ash/content/help_app_ui/search/search_handler.h
rename to chromeos/components/help_app_ui/search/search_handler.h
index cd62a0a..37f0ac7 100644
--- a/ash/content/help_app_ui/search/search_handler.h
+++ b/chromeos/components/help_app_ui/search/search_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 ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_HANDLER_H_
-#define ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_HANDLER_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_HANDLER_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_HANDLER_H_
 
 #include <vector>
 
-#include "ash/content/help_app_ui/search/search.mojom.h"
-#include "ash/content/help_app_ui/search/search_tag_registry.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
+#include "chromeos/components/help_app_ui/search/search_tag_registry.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy.h"
 #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -88,4 +88,4 @@
 }  // namespace help_app
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_HANDLER_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_HANDLER_H_
diff --git a/ash/content/help_app_ui/search/search_handler_unittest.cc b/chromeos/components/help_app_ui/search/search_handler_unittest.cc
similarity index 97%
rename from ash/content/help_app_ui/search/search_handler_unittest.cc
rename to chromeos/components/help_app_ui/search/search_handler_unittest.cc
index 9ac8ed5..2d0fa35 100644
--- a/ash/content/help_app_ui/search/search_handler_unittest.cc
+++ b/chromeos/components/help_app_ui/search/search_handler_unittest.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 "ash/content/help_app_ui/search/search_handler.h"
+#include "chromeos/components/help_app_ui/search/search_handler.h"
 
-#include "ash/content/help_app_ui/search/search.mojom-test-utils.h"
-#include "ash/content/help_app_ui/search/search_tag_registry.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
+#include "chromeos/components/help_app_ui/search/search.mojom-test-utils.h"
+#include "chromeos/components/help_app_ui/search/search_tag_registry.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/content/help_app_ui/search/search_metadata.cc b/chromeos/components/help_app_ui/search/search_metadata.cc
similarity index 90%
rename from ash/content/help_app_ui/search/search_metadata.cc
rename to chromeos/components/help_app_ui/search/search_metadata.cc
index fc6c31d..9d01c144 100644
--- a/ash/content/help_app_ui/search/search_metadata.cc
+++ b/chromeos/components/help_app_ui/search/search_metadata.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/content/help_app_ui/search/search_metadata.h"
+#include "chromeos/components/help_app_ui/search/search_metadata.h"
 
 namespace chromeos {
 namespace help_app {
diff --git a/ash/content/help_app_ui/search/search_metadata.h b/chromeos/components/help_app_ui/search/search_metadata.h
similarity index 87%
rename from ash/content/help_app_ui/search/search_metadata.h
rename to chromeos/components/help_app_ui/search/search_metadata.h
index 3041634..408e329 100644
--- a/ash/content/help_app_ui/search/search_metadata.h
+++ b/chromeos/components/help_app_ui/search/search_metadata.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_CONTENT_HELP_APP_UI_SEARCH_SEARCH_METADATA_H_
-#define ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_METADATA_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_METADATA_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_METADATA_H_
 
 #include <string>
 
@@ -40,4 +40,4 @@
 }  // namespace help_app
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_METADATA_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_METADATA_H_
diff --git a/ash/content/help_app_ui/search/search_tag_registry.cc b/chromeos/components/help_app_ui/search/search_tag_registry.cc
similarity index 95%
rename from ash/content/help_app_ui/search/search_tag_registry.cc
rename to chromeos/components/help_app_ui/search/search_tag_registry.cc
index 51ece6f..03ac616e 100644
--- a/ash/content/help_app_ui/search/search_tag_registry.cc
+++ b/chromeos/components/help_app_ui/search/search_tag_registry.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 "ash/content/help_app_ui/search/search_tag_registry.h"
+#include "chromeos/components/help_app_ui/search/search_tag_registry.h"
 
 #include <utility>
 
-#include "ash/content/help_app_ui/search/search_metadata.h"
 #include "base/bind.h"
 #include "base/strings/string_number_conversions.h"
+#include "chromeos/components/help_app_ui/search/search_metadata.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy.h"
 
 namespace chromeos {
diff --git a/ash/content/help_app_ui/search/search_tag_registry.h b/chromeos/components/help_app_ui/search/search_tag_registry.h
similarity index 87%
rename from ash/content/help_app_ui/search/search_tag_registry.h
rename to chromeos/components/help_app_ui/search/search_tag_registry.h
index 206dbb0..1ff480c 100644
--- a/ash/content/help_app_ui/search/search_tag_registry.h
+++ b/chromeos/components/help_app_ui/search/search_tag_registry.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 ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_TAG_REGISTRY_H_
-#define ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_TAG_REGISTRY_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_TAG_REGISTRY_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_TAG_REGISTRY_H_
 
 #include <string>
 #include <unordered_map>
 #include <vector>
 
-#include "ash/content/help_app_ui/search/search.mojom.h"
-#include "ash/content/help_app_ui/search/search_metadata.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
+#include "chromeos/components/help_app_ui/search/search_metadata.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy.h"
 #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -73,4 +73,4 @@
 }  // namespace help_app
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_SEARCH_SEARCH_TAG_REGISTRY_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_SEARCH_SEARCH_TAG_REGISTRY_H_
diff --git a/ash/content/help_app_ui/search/search_tag_registry_unittest.cc b/chromeos/components/help_app_ui/search/search_tag_registry_unittest.cc
similarity index 96%
rename from ash/content/help_app_ui/search/search_tag_registry_unittest.cc
rename to chromeos/components/help_app_ui/search/search_tag_registry_unittest.cc
index 89575d9..d2b027c4 100644
--- a/ash/content/help_app_ui/search/search_tag_registry_unittest.cc
+++ b/chromeos/components/help_app_ui/search/search_tag_registry_unittest.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/content/help_app_ui/search/search_tag_registry.h"
+#include "chromeos/components/help_app_ui/search/search_tag_registry.h"
 
-#include "ash/content/help_app_ui/search/search.mojom.h"
-#include "ash/content/help_app_ui/search/search_metadata.h"
 #include "base/test/task_environment.h"
+#include "chromeos/components/help_app_ui/search/search.mojom.h"
+#include "chromeos/components/help_app_ui/search/search_metadata.h"
 #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/content/help_app_ui/test/DEPS b/chromeos/components/help_app_ui/test/DEPS
similarity index 100%
rename from ash/content/help_app_ui/test/DEPS
rename to chromeos/components/help_app_ui/test/DEPS
diff --git a/ash/content/help_app_ui/test/driver.js b/chromeos/components/help_app_ui/test/driver.js
similarity index 100%
rename from ash/content/help_app_ui/test/driver.js
rename to chromeos/components/help_app_ui/test/driver.js
diff --git a/ash/content/help_app_ui/test/driver_api.js b/chromeos/components/help_app_ui/test/driver_api.js
similarity index 100%
rename from ash/content/help_app_ui/test/driver_api.js
rename to chromeos/components/help_app_ui/test/driver_api.js
diff --git a/ash/content/help_app_ui/test/guest_query_receiver.js b/chromeos/components/help_app_ui/test/guest_query_receiver.js
similarity index 100%
rename from ash/content/help_app_ui/test/guest_query_receiver.js
rename to chromeos/components/help_app_ui/test/guest_query_receiver.js
diff --git a/ash/content/help_app_ui/test/help_app_guest_ui_browsertest.js b/chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js
similarity index 100%
rename from ash/content/help_app_ui/test/help_app_guest_ui_browsertest.js
rename to chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js
diff --git a/ash/content/help_app_ui/test/help_app_ui_browsertest.cc b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc
similarity index 68%
rename from ash/content/help_app_ui/test/help_app_ui_browsertest.cc
rename to chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc
index ce18f901..81d6a954 100644
--- a/ash/content/help_app_ui/test/help_app_ui_browsertest.cc
+++ b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/content/help_app_ui/test/help_app_ui_browsertest.h"
+#include "chromeos/components/help_app_ui/test/help_app_ui_browsertest.h"
 
-#include "ash/content/help_app_ui/url_constants.h"
 #include "base/files/file_path.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/web_applications/test/sandboxed_web_ui_test_base.h"
 
-constexpr base::FilePath::CharType kHelpAppGuestTestApi[] =
-    FILE_PATH_LITERAL("ash/content/help_app_ui/test/guest_query_receiver.js");
+constexpr base::FilePath::CharType kHelpAppGuestTestApi[] = FILE_PATH_LITERAL(
+    "chromeos/components/help_app_ui/test/guest_query_receiver.js");
 
 // Test cases that run in the guest context.
 constexpr base::FilePath::CharType kGuestTestCases[] = FILE_PATH_LITERAL(
-    "ash/content/help_app_ui/test/help_app_guest_ui_browsertest.js");
+    "chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js");
 
 HelpAppUiBrowserTest::HelpAppUiBrowserTest()
     : SandboxedWebUiAppTestBase(chromeos::kChromeUIHelpAppURL,
diff --git a/ash/content/help_app_ui/test/help_app_ui_browsertest.h b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.h
similarity index 70%
rename from ash/content/help_app_ui/test/help_app_ui_browsertest.h
rename to chromeos/components/help_app_ui/test/help_app_ui_browsertest.h
index c82a9a3a..83920d6f 100644
--- a/ash/content/help_app_ui/test/help_app_ui_browsertest.h
+++ b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.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_CONTENT_HELP_APP_UI_TEST_HELP_APP_UI_BROWSERTEST_H_
-#define ASH_CONTENT_HELP_APP_UI_TEST_HELP_APP_UI_BROWSERTEST_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_TEST_HELP_APP_UI_BROWSERTEST_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_TEST_HELP_APP_UI_BROWSERTEST_H_
 
 #include "chromeos/components/web_applications/test/sandboxed_web_ui_test_base.h"
 
@@ -16,4 +16,4 @@
   HelpAppUiBrowserTest& operator=(const HelpAppUiBrowserTest&) = delete;
 };
 
-#endif  // ASH_CONTENT_HELP_APP_UI_TEST_HELP_APP_UI_BROWSERTEST_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_TEST_HELP_APP_UI_BROWSERTEST_H_
diff --git a/ash/content/help_app_ui/test/help_app_ui_browsertest.js b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
similarity index 94%
rename from ash/content/help_app_ui/test/help_app_ui_browsertest.js
rename to chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
index b34982b..53be207 100644
--- a/ash/content/help_app_ui/test/help_app_ui_browsertest.js
+++ b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
@@ -6,7 +6,7 @@
  * @fileoverview Test suite for chrome://help-app.
  */
 
-GEN('#include "ash/content/help_app_ui/test/help_app_ui_browsertest.h"');
+GEN('#include "chromeos/components/help_app_ui/test/help_app_ui_browsertest.h"');
 
 GEN('#include "ash/constants/ash_features.h"');
 GEN('#include "content/public/test/browser_test.h"');
@@ -23,7 +23,7 @@
   get extraLibraries() {
     return [
       ...super.extraLibraries,
-      '//ash/content/help_app_ui/test/driver.js',
+      '//chromeos/components/help_app_ui/test/driver.js',
       '//ui/webui/resources/js/assert.js',
     ];
   }
diff --git a/ash/content/help_app_ui/url_constants.cc b/chromeos/components/help_app_ui/url_constants.cc
similarity index 89%
rename from ash/content/help_app_ui/url_constants.cc
rename to chromeos/components/help_app_ui/url_constants.cc
index e5ea33e..5cb30ee 100644
--- a/ash/content/help_app_ui/url_constants.cc
+++ b/chromeos/components/help_app_ui/url_constants.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/content/help_app_ui/url_constants.h"
+#include "chromeos/components/help_app_ui/url_constants.h"
 
 namespace chromeos {
 
diff --git a/ash/content/help_app_ui/url_constants.h b/chromeos/components/help_app_ui/url_constants.h
similarity index 70%
rename from ash/content/help_app_ui/url_constants.h
rename to chromeos/components/help_app_ui/url_constants.h
index 4aa40a3..0aa5a898 100644
--- a/ash/content/help_app_ui/url_constants.h
+++ b/chromeos/components/help_app_ui/url_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_CONTENT_HELP_APP_UI_URL_CONSTANTS_H_
-#define ASH_CONTENT_HELP_APP_UI_URL_CONSTANTS_H_
+#ifndef CHROMEOS_COMPONENTS_HELP_APP_UI_URL_CONSTANTS_H_
+#define CHROMEOS_COMPONENTS_HELP_APP_UI_URL_CONSTANTS_H_
 
 namespace chromeos {
 
@@ -14,4 +14,4 @@
 
 }  // namespace chromeos
 
-#endif  // ASH_CONTENT_HELP_APP_UI_URL_CONSTANTS_H_
+#endif  // CHROMEOS_COMPONENTS_HELP_APP_UI_URL_CONSTANTS_H_
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc
index 5bdb6b3..40c6e7f 100644
--- a/chromeos/dbus/cros_disks_client.cc
+++ b/chromeos/dbus/cros_disks_client.cc
@@ -34,6 +34,7 @@
 #include "dbus/object_path.h"
 #include "dbus/object_proxy.h"
 #include "dbus/values_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
@@ -741,10 +742,10 @@
   properties->GetStringWithoutPathExpansion(cros_disks::kFileSystemType,
                                             &file_system_type_);
 
-  properties->GetIntegerWithoutPathExpansion(cros_disks::kBusNumber,
-                                             &bus_number_);
-  properties->GetIntegerWithoutPathExpansion(cros_disks::kDeviceNumber,
-                                             &device_number_);
+  bus_number_ =
+      properties->FindIntKey(cros_disks::kBusNumber).value_or(bus_number_);
+  device_number_ = properties->FindIntKey(cros_disks::kDeviceNumber)
+                       .value_or(device_number_);
 
   // dbus::PopDataAsValue() pops uint64_t as double.
   // The top 11 bits of uint64_t are dropped by the use of double. But, this
diff --git a/chromeos/geolocation/simple_geolocation_request.cc b/chromeos/geolocation/simple_geolocation_request.cc
index 5d31abc..1ad792f 100644
--- a/chromeos/geolocation/simple_geolocation_request.cc
+++ b/chromeos/geolocation/simple_geolocation_request.cc
@@ -231,8 +231,8 @@
     }
 
     // Ignore result (code defaults to zero).
-    error_object->GetIntegerWithoutPathExpansion(kCodeString,
-                                                 &(position->error_code));
+    position->error_code =
+        error_object->FindIntKey(kCodeString).value_or(position->error_code);
   } else {
     position->error_message.erase();
   }
diff --git a/chromeos/login/auth/test_attempt_state.h b/chromeos/login/auth/test_attempt_state.h
index b515985..51e88a4 100644
--- a/chromeos/login/auth/test_attempt_state.h
+++ b/chromeos/login/auth/test_attempt_state.h
@@ -19,7 +19,7 @@
 class COMPONENT_EXPORT(CHROMEOS_LOGIN_AUTH) TestAttemptState
     : public AuthAttemptState {
  public:
-  explicit TestAttemptState(const UserContext& credentials);
+  TestAttemptState(const UserContext& credentials);
 
   ~TestAttemptState() override;
 
diff --git a/chromeos/login/login_state/scoped_test_public_session_login_state.h b/chromeos/login/login_state/scoped_test_public_session_login_state.h
index f0754ab..46053a9 100644
--- a/chromeos/login/login_state/scoped_test_public_session_login_state.h
+++ b/chromeos/login/login_state/scoped_test_public_session_login_state.h
@@ -15,7 +15,7 @@
 // (so it nicely cleans up after going out of scope).
 class ScopedTestPublicSessionLoginState {
  public:
-  explicit ScopedTestPublicSessionLoginState(
+  ScopedTestPublicSessionLoginState(
       LoginState::LoggedInUserType user_type =
           LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);
   ~ScopedTestPublicSessionLoginState();
diff --git a/chromeos/network/network_device_handler_unittest.cc b/chromeos/network/network_device_handler_unittest.cc
index a23dff329..302549e 100644
--- a/chromeos/network/network_device_handler_unittest.cc
+++ b/chromeos/network/network_device_handler_unittest.cc
@@ -20,6 +20,7 @@
 #include "chromeos/network/network_handler_callbacks.h"
 #include "chromeos/network/network_state_handler.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
@@ -161,10 +162,10 @@
   // GetDeviceProperties should return the value set by SetDeviceProperty.
   GetDeviceProperties(kDefaultCellularDevicePath, kResultSuccess);
 
-  int interval = 0;
-  EXPECT_TRUE(properties_->GetIntegerWithoutPathExpansion(
-      shill::kScanIntervalProperty, &interval));
-  EXPECT_EQ(1, interval);
+  absl::optional<int> interval =
+      properties_->FindIntKey(shill::kScanIntervalProperty);
+  EXPECT_TRUE(interval.has_value());
+  EXPECT_EQ(1, interval.value());
 
   // Repeat the same with value false.
   network_device_handler_->SetDeviceProperty(
@@ -175,9 +176,9 @@
 
   GetDeviceProperties(kDefaultCellularDevicePath, kResultSuccess);
 
-  EXPECT_TRUE(properties_->GetIntegerWithoutPathExpansion(
-      shill::kScanIntervalProperty, &interval));
-  EXPECT_EQ(2, interval);
+  interval = properties_->FindIntKey(shill::kScanIntervalProperty);
+  EXPECT_TRUE(interval.has_value());
+  EXPECT_EQ(2, interval.value());
 
   // Set property on an invalid path.
   network_device_handler_->SetDeviceProperty(
diff --git a/chromeos/network/network_state_unittest.cc b/chromeos/network/network_state_unittest.cc
index c3b18d2..cfae02c 100644
--- a/chromeos/network/network_state_unittest.cc
+++ b/chromeos/network/network_state_unittest.cc
@@ -18,6 +18,7 @@
 #include "chromeos/network/network_state_test_helper.h"
 #include "chromeos/network/tether_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
@@ -345,15 +346,15 @@
   base::DictionaryValue dictionary;
   network_state_.GetStateProperties(&dictionary);
 
-  int signal_strength;
-  EXPECT_TRUE(dictionary.GetIntegerWithoutPathExpansion(kTetherSignalStrength,
-                                                        &signal_strength));
-  EXPECT_EQ(75, signal_strength);
+  absl::optional<int> signal_strength =
+      dictionary.FindIntKey(kTetherSignalStrength);
+  EXPECT_TRUE(signal_strength.has_value());
+  EXPECT_EQ(75, signal_strength.value());
 
-  int battery_percentage;
-  EXPECT_TRUE(dictionary.GetIntegerWithoutPathExpansion(
-      kTetherBatteryPercentage, &battery_percentage));
-  EXPECT_EQ(85, battery_percentage);
+  absl::optional<int> battery_percentage =
+      dictionary.FindIntKey(kTetherBatteryPercentage);
+  EXPECT_TRUE(battery_percentage.has_value());
+  EXPECT_EQ(85, battery_percentage.value());
 
   bool tether_has_connected_to_host;
   EXPECT_TRUE(dictionary.GetBooleanWithoutPathExpansion(
diff --git a/chromeos/network/onc/onc_normalizer.cc b/chromeos/network/onc/onc_normalizer.cc
index 5cfda571..7a1d5cf4 100644
--- a/chromeos/network/onc/onc_normalizer.cc
+++ b/chromeos/network/onc/onc_normalizer.cc
@@ -157,9 +157,7 @@
                     ::onc::client_cert::kClientCertRef,
                     clientcert_type == ::onc::client_cert::kRef);
 
-  int ike_version = -1;
-  ipsec->GetIntegerWithoutPathExpansion(::onc::ipsec::kIKEVersion,
-                                        &ike_version);
+  int ike_version = ipsec->FindIntKey(::onc::ipsec::kIKEVersion).value_or(-1);
   RemoveEntryUnless(ipsec, ::onc::ipsec::kEAP, ike_version == 2);
   RemoveEntryUnless(ipsec, ::onc::ipsec::kGroup, ike_version == 1);
   RemoveEntryUnless(ipsec, ::onc::ipsec::kXAUTH, ike_version == 1);
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc
index 12416b35..77b91544 100644
--- a/chromeos/network/onc/onc_validator.cc
+++ b/chromeos/network/onc/onc_validator.cc
@@ -23,6 +23,7 @@
 #include "components/crx_file/id_util.h"
 #include "components/device_event_log/device_event_log.h"
 #include "components/onc/onc_constants.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace chromeos {
 namespace onc {
@@ -418,15 +419,15 @@
                                            const std::string& field_name,
                                            int lower_bound,
                                            int upper_bound) {
-  int actual_value;
-  if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
-      (lower_bound <= actual_value && actual_value <= upper_bound)) {
+  absl::optional<int> actual_value = object.FindIntKey(field_name);
+  if (!actual_value || (lower_bound <= actual_value.value() &&
+                        actual_value.value() <= upper_bound)) {
     return false;
   }
 
   path_.push_back(field_name);
   std::ostringstream msg;
-  msg << "Found value '" << actual_value
+  msg << "Found value '" << actual_value.value()
       << "', but expected a value in the range [" << lower_bound << ", "
       << upper_bound << "] (boundaries inclusive)";
   AddValidationIssue(true /* is_error */, msg.str());
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt
index 97138394..0e80bec 100644
--- a/chromeos/profiles/orderfile.newest.txt
+++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@
-chromeos-chrome-orderfile-field-92-4484.0-1621849150-benchmark-92.0.4515.9-r1.orderfile.xz
+chromeos-chrome-orderfile-field-92-4484.0-1621849150-benchmark-92.0.4515.32-r1.orderfile.xz
diff --git a/chromeos/resources/BUILD.gn b/chromeos/resources/BUILD.gn
index 2acd9d4..2d20410 100644
--- a/chromeos/resources/BUILD.gn
+++ b/chromeos/resources/BUILD.gn
@@ -8,6 +8,7 @@
 
 import("//chromeos/assistant/assistant.gni")
 import("//chromeos/components/eche_app_ui/eche_app_ui.gni")
+import("//chromeos/components/help_app_ui/help_app_ui.gni")
 import("//chromeos/components/media_app_ui/media_app_ui.gni")
 import("//tools/grit/grit_rule.gni")
 
@@ -85,6 +86,65 @@
   output_dir = "$root_gen_dir/chromeos"
 }
 
+# Resources used by chrome://help-app, and parts of the sandboxed app it hosts
+# that do not come from the app bundle (below).
+grit("help_app_resources") {
+  source = "../components/help_app_ui/resources/help_app_resources.grd"
+
+  outputs = [
+    "grit/chromeos_help_app_resources.h",
+    "grit/chromeos_help_app_resources_map.cc",
+    "grit/chromeos_help_app_resources_map.h",
+    "chromeos_help_app_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chromeos"
+
+  deps = [
+    "//chromeos/components/help_app_ui:mojo_bindings_js",
+    "//chromeos/components/help_app_ui/search:mojo_bindings_js",
+    "//chromeos/components/local_search_service/public/mojom:mojom_js",
+  ]
+}
+
+# Resources automatically served by the chrome://help-app bundle, obtained via DEPS.
+grit("help_app_bundle_resources") {
+  if (enable_cros_help_app) {
+    # Obtained via an internal CIPD package in src/DEPS.
+    source =
+        "../components/help_app_ui/resources/prod/help_app_bundle_resources.grd"
+  } else {
+    source = "../components/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd"
+  }
+
+  use_brotli = true
+
+  outputs = [
+    "grit/chromeos_help_app_bundle_resources.h",
+    "grit/chromeos_help_app_bundle_resources_map.cc",
+    "grit/chromeos_help_app_bundle_resources_map.h",
+    "chromeos_help_app_bundle_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chromeos"
+}
+
+grit("help_app_kids_magazine_bundle_resources") {
+  if (enable_cros_help_app) {
+    source = "../components/help_app_ui/resources/prod/help_app_kids_magazine_bundle_resources.grd"
+  } else {
+    source = "../components/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd"
+  }
+
+  use_brotli = true
+
+  outputs = [
+    "grit/chromeos_help_app_kids_magazine_bundle_resources.h",
+    "grit/chromeos_help_app_kids_magazine_bundle_resources_map.cc",
+    "grit/chromeos_help_app_kids_magazine_bundle_resources_map.h",
+    "chromeos_help_app_kids_magazine_bundle_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chromeos"
+}
+
 if (!is_official_build) {
   # Resources used by chrome://sample-system-web-app
   grit("sample_system_web_app_resources") {
diff --git a/chromeos/ui/base/window_state_type.cc b/chromeos/ui/base/window_state_type.cc
index c4847dd..ee70af26 100644
--- a/chromeos/ui/base/window_state_type.cc
+++ b/chromeos/ui/base/window_state_type.cc
@@ -22,9 +22,9 @@
       return stream << "kInactive";
     case WindowStateType::kFullscreen:
       return stream << "kFullscreen";
-    case WindowStateType::kLeftSnapped:
+    case WindowStateType::kPrimarySnapped:
       return stream << "kLeftSnapped";
-    case WindowStateType::kRightSnapped:
+    case WindowStateType::kSecondarySnapped:
       return stream << "kRightSnapped";
     case WindowStateType::kAutoPositioned:
       return stream << "kAutoPositioned";
@@ -65,8 +65,8 @@
     case WindowStateType::kDefault:
       return ui::SHOW_STATE_DEFAULT;
     case WindowStateType::kNormal:
-    case WindowStateType::kRightSnapped:
-    case WindowStateType::kLeftSnapped:
+    case WindowStateType::kSecondarySnapped:
+    case WindowStateType::kPrimarySnapped:
     case WindowStateType::kAutoPositioned:
     case WindowStateType::kPip:
       return ui::SHOW_STATE_NORMAL;
@@ -112,8 +112,8 @@
          value == int64_t(WindowStateType::kMaximized) ||
          value == int64_t(WindowStateType::kInactive) ||
          value == int64_t(WindowStateType::kFullscreen) ||
-         value == int64_t(WindowStateType::kLeftSnapped) ||
-         value == int64_t(WindowStateType::kRightSnapped) ||
+         value == int64_t(WindowStateType::kPrimarySnapped) ||
+         value == int64_t(WindowStateType::kSecondarySnapped) ||
          value == int64_t(WindowStateType::kAutoPositioned) ||
          value == int64_t(WindowStateType::kPinned) ||
          value == int64_t(WindowStateType::kTrustedPinned) ||
diff --git a/chromeos/ui/base/window_state_type.h b/chromeos/ui/base/window_state_type.h
index 94c1080..12c0997 100644
--- a/chromeos/ui/base/window_state_type.h
+++ b/chromeos/ui/base/window_state_type.h
@@ -28,8 +28,8 @@
   kFullscreen,
 
   // Additional ash states.
-  kLeftSnapped,
-  kRightSnapped,
+  kPrimarySnapped,
+  kSecondarySnapped,
 
   // A window is in this state when it is automatically placed and
   // sized by the window manager. (it's newly opened, or pushed to the side
diff --git a/components/BUILD.gn b/components/BUILD.gn
index a30d95ea..e0be7ab 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -241,6 +241,7 @@
     ]
   } else {  # !is_ios
     deps += [
+      "//components/accuracy_tips:unit_tests",
       "//components/android_autofill/browser:unit_tests",
       "//components/autofill/content/browser:unit_tests",
       "//components/autofill/content/renderer:unit_tests",
diff --git a/components/accuracy_tips/BUILD.gn b/components/accuracy_tips/BUILD.gn
new file mode 100644
index 0000000..f737127
--- /dev/null
+++ b/components/accuracy_tips/BUILD.gn
@@ -0,0 +1,39 @@
+# Copyright 2021 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.
+
+static_library("accuracy_tips") {
+  sources = [
+    "accuracy_service.cc",
+    "accuracy_service.h",
+    "accuracy_tip_status.h",
+    "accuracy_tip_ui.h",
+    "accuracy_web_contents_observer.cc",
+    "accuracy_web_contents_observer.h",
+    "features.cc",
+    "features.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//content/public/browser",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "accuracy_service_unittest.cc",
+    "accuracy_web_contents_observer_unittest.cc",
+  ]
+
+  deps = [
+    ":accuracy_tips",
+    "//base/test:test_support",
+    "//content/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/accuracy_tips/DEPS b/components/accuracy_tips/DEPS
new file mode 100644
index 0000000..d5b468d
--- /dev/null
+++ b/components/accuracy_tips/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+    "+content/public/common",
+    "+content/public/browser",
+    "+content/public/test",
+    "+components/keyed_service/core",
+]
+
diff --git a/components/accuracy_tips/DIR_METADATA b/components/accuracy_tips/DIR_METADATA
new file mode 100644
index 0000000..db7a5c4a
--- /dev/null
+++ b/components/accuracy_tips/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Privacy"
+}
diff --git a/components/accuracy_tips/OWNERS b/components/accuracy_tips/OWNERS
new file mode 100644
index 0000000..96e76c33
--- /dev/null
+++ b/components/accuracy_tips/OWNERS
@@ -0,0 +1,2 @@
+dullweber@chromium.org
+eokoyomon@chromium.org
diff --git a/components/accuracy_tips/README b/components/accuracy_tips/README
new file mode 100644
index 0000000..7644e9b
--- /dev/null
+++ b/components/accuracy_tips/README
@@ -0,0 +1,8 @@
+This directory stores files related to Chrome's accuracy tips.
+
+If Chrome believes a site a user is visiting is low accuracy, Chrome may
+show a pop-up while visiting the page. This popup won't block users from
+entering a site and it will be strictly rate-limited to avoid being annoying.
+
+Currently this code is only used for Chrome on desktop but in the long term
+we have plans for Android and iOS and potentially Weblayer as well.
diff --git a/components/accuracy_tips/accuracy_service.cc b/components/accuracy_tips/accuracy_service.cc
new file mode 100644
index 0000000..539ad64
--- /dev/null
+++ b/components/accuracy_tips/accuracy_service.cc
@@ -0,0 +1,45 @@
+// Copyright 2021 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/accuracy_tips/accuracy_service.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_refptr.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+#include "components/accuracy_tips/accuracy_tip_ui.h"
+#include "components/accuracy_tips/features.h"
+
+namespace accuracy_tips {
+
+AccuracyService::AccuracyService(std::unique_ptr<AccuracyTipUI> ui)
+    : ui_(std::move(ui)), sample_url_(GURL(kSampleUrl.Get())) {}
+
+AccuracyService::~AccuracyService() = default;
+
+void AccuracyService::CheckAccuracyStatus(const GURL& url,
+                                          AccuracyCheckCallback callback) {
+  // TODO(crbug.com/1210891): Implement check.
+  if (sample_url_.is_valid() && url == sample_url_) {
+    std::move(callback).Run(AccuracyTipStatus::kMisinformation);
+    return;
+  }
+
+  std::move(callback).Run(AccuracyTipStatus::kNone);
+}
+
+void AccuracyService::MaybeShowAccuracyTip(content::WebContents* web_contents) {
+  // TODO(crbug.com/1210891): Implement rate limiting.
+  if (!ui_)
+    return;
+  ui_->ShowAccuracyTip(web_contents, AccuracyTipStatus::kMisinformation,
+                       base::BindOnce(&AccuracyService::OnAccuracyTipClosed,
+                                      weak_factory_.GetWeakPtr()));
+}
+
+void AccuracyService::OnAccuracyTipClosed(
+    AccuracyTipUI::Interaction interaction) {
+  // TODO(crbug.com/1210891): Log histograms.
+}
+
+}  // namespace accuracy_tips
diff --git a/components/accuracy_tips/accuracy_service.h b/components/accuracy_tips/accuracy_service.h
new file mode 100644
index 0000000..2bb5bb8
--- /dev/null
+++ b/components/accuracy_tips/accuracy_service.h
@@ -0,0 +1,52 @@
+// Copyright 2021 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_ACCURACY_TIPS_ACCURACY_SERVICE_H_
+#define COMPONENTS_ACCURACY_TIPS_ACCURACY_SERVICE_H_
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+#include "components/accuracy_tips/accuracy_tip_ui.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "url/gurl.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace accuracy_tips {
+
+// Checks accuracy information on URLs for AccuracyTips.
+// Handles rate-limiting and feature checks.
+class AccuracyService : public KeyedService {
+ public:
+  explicit AccuracyService(std::unique_ptr<AccuracyTipUI> ui);
+  ~AccuracyService() override;
+
+  AccuracyService(const AccuracyService&) = delete;
+  AccuracyService& operator=(const AccuracyService&) = delete;
+
+  // Callback for accuracy check result.
+  using AccuracyCheckCallback = base::OnceCallback<void(AccuracyTipStatus)>;
+
+  // Returns the accuracy status for |url|.
+  virtual void CheckAccuracyStatus(const GURL& url,
+                                   AccuracyCheckCallback callback);
+
+  // Shows an accuracy tip UI for web_contents after checking rate limits.
+  virtual void MaybeShowAccuracyTip(content::WebContents* web_contents);
+
+ private:
+  void OnAccuracyTipClosed(AccuracyTipUI::Interaction interaction);
+
+  std::unique_ptr<AccuracyTipUI> ui_;
+  GURL sample_url_;
+
+  base::WeakPtrFactory<AccuracyService> weak_factory_{this};
+};
+
+}  // namespace accuracy_tips
+
+#endif  // COMPONENTS_ACCURACY_TIPS_ACCURACY_SERVICE_H_
diff --git a/components/accuracy_tips/accuracy_service_unittest.cc b/components/accuracy_tips/accuracy_service_unittest.cc
new file mode 100644
index 0000000..f254d9bf
--- /dev/null
+++ b/components/accuracy_tips/accuracy_service_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2021 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/accuracy_tips/accuracy_service.h"
+#include <memory>
+
+#include "base/metrics/field_trial_params.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+#include "components/accuracy_tips/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+
+namespace accuracy_tips {
+
+class MockAccuracyTipUI : public AccuracyTipUI {
+ public:
+  MOCK_METHOD3(ShowAccuracyTip,
+               void(content::WebContents*,
+                    AccuracyTipStatus,
+                    base::OnceCallback<void(Interaction)>));
+};
+
+class AccuracyServiceTest : public ::testing::Test {
+ protected:
+  AccuracyServiceTest() = default;
+
+  void SetUp() override {
+    base::FieldTrialParams params;
+    params[kSampleUrl.name] = "https://badurl.com";
+    feature_list.InitAndEnableFeatureWithParameters(kAccuracyTipsFeature,
+                                                    params);
+    auto ui = std::make_unique<testing::StrictMock<MockAccuracyTipUI>>();
+    ui_ = ui.get();
+    service_ = std::make_unique<AccuracyService>(std::move(ui));
+  }
+
+  AccuracyService* service() { return service_.get(); }
+  MockAccuracyTipUI* ui() { return ui_; }
+
+ private:
+  base::test::ScopedFeatureList feature_list;
+  std::unique_ptr<AccuracyService> service_;
+  MockAccuracyTipUI* ui_;
+};
+
+TEST_F(AccuracyServiceTest, CheckAccuracyStatusForRandomSite) {
+  base::MockOnceCallback<void(AccuracyTipStatus)> callback;
+  EXPECT_CALL(callback, Run(AccuracyTipStatus::kNone));
+  service()->CheckAccuracyStatus(GURL("https://example.com"), callback.Get());
+}
+
+TEST_F(AccuracyServiceTest, CheckAccuracyStatusForSampleUrl) {
+  base::MockOnceCallback<void(AccuracyTipStatus)> callback;
+  EXPECT_CALL(callback, Run(AccuracyTipStatus::kMisinformation));
+  service()->CheckAccuracyStatus(GURL("https://badurl.com"), callback.Get());
+}
+
+TEST_F(AccuracyServiceTest, ShowUI) {
+  EXPECT_CALL(*ui(), ShowAccuracyTip(_, _, _));
+  service()->MaybeShowAccuracyTip(nullptr);
+}
+
+}  // namespace accuracy_tips
\ No newline at end of file
diff --git a/components/accuracy_tips/accuracy_tip_status.h b/components/accuracy_tips/accuracy_tip_status.h
new file mode 100644
index 0000000..cc373fde
--- /dev/null
+++ b/components/accuracy_tips/accuracy_tip_status.h
@@ -0,0 +1,20 @@
+// Copyright 2021 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_ACCURACY_TIPS_ACCURACY_TIP_STATUS_H_
+#define COMPONENTS_ACCURACY_TIPS_ACCURACY_TIP_STATUS_H_
+
+namespace accuracy_tips {
+
+// Represents the different results of the accuracy check.
+enum class AccuracyTipStatus {
+  // No accuracy information for the site.
+  kNone = 0,
+  // Site classified as being misleading.
+  kMisinformation = 1,
+};
+
+}  // namespace accuracy_tips
+
+#endif  // COMPONENTS_ACCURACY_TIPS_ACCURACY_TIP_STATUS_H_
\ No newline at end of file
diff --git a/components/accuracy_tips/accuracy_tip_ui.h b/components/accuracy_tips/accuracy_tip_ui.h
new file mode 100644
index 0000000..058936d0
--- /dev/null
+++ b/components/accuracy_tips/accuracy_tip_ui.h
@@ -0,0 +1,48 @@
+// Copyright 2021 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_ACCURACY_TIPS_ACCURACY_TIP_UI_H_
+#define COMPONENTS_ACCURACY_TIPS_ACCURACY_TIP_UI_H_
+
+#include "base/callback.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace accuracy_tips {
+
+// Abstract class that creates a platform-specific UI for accuracy tips.
+class AccuracyTipUI {
+ public:
+  AccuracyTipUI() = default;
+  virtual ~AccuracyTipUI() = default;
+
+  AccuracyTipUI(const AccuracyTipUI&) = delete;
+  AccuracyTipUI& operator=(const AccuracyTipUI&) = delete;
+
+  // Represents the different user interactions with a AccuracyTip dialog.
+  enum class Interaction {
+    kNoAction = 0,
+    kDismiss = 1,
+    kIgnore = 2,
+    kLearnMore = 3,
+
+    kMaxValue = kLearnMore,
+  };
+
+  // Shows AccuracyTip UI using the specified information if it is not already
+  // showing. |close_callback| will be called when
+  // the dialog is closed; the argument indicates the action that the user took
+  // (if any) to close the dialog.
+  virtual void ShowAccuracyTip(
+      content::WebContents* web_contents,
+      AccuracyTipStatus type,
+      base::OnceCallback<void(Interaction)> close_callback) = 0;
+};
+
+}  // namespace accuracy_tips
+
+#endif  // COMPONENTS_ACCURACY_TIPS_ACCURACY_TIP_UI_H_
diff --git a/components/accuracy_tips/accuracy_web_contents_observer.cc b/components/accuracy_tips/accuracy_web_contents_observer.cc
new file mode 100644
index 0000000..5677aaf3
--- /dev/null
+++ b/components/accuracy_tips/accuracy_web_contents_observer.cc
@@ -0,0 +1,72 @@
+// Copyright 2021 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/accuracy_tips/accuracy_web_contents_observer.h"
+
+#include "components/accuracy_tips/accuracy_service.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+#include "components/accuracy_tips/features.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/common/page_visibility_state.h"
+#include "url/gurl.h"
+
+namespace accuracy_tips {
+
+// static
+bool AccuracyWebContentsObserver::IsEnabled(
+    content::WebContents* web_contents) {
+  return base::FeatureList::IsEnabled(kAccuracyTipsFeature) &&
+         !web_contents->GetBrowserContext()->IsOffTheRecord();
+}
+
+AccuracyWebContentsObserver::~AccuracyWebContentsObserver() = default;
+
+AccuracyWebContentsObserver::AccuracyWebContentsObserver(
+    content::WebContents* web_contents,
+    AccuracyService* accuracy_service)
+    : WebContentsObserver(web_contents), accuracy_service_(accuracy_service) {
+  DCHECK(web_contents);
+  DCHECK(!web_contents->GetBrowserContext()->IsOffTheRecord());
+  DCHECK(accuracy_service);
+}
+
+void AccuracyWebContentsObserver::DidFinishNavigation(
+    content::NavigationHandle* navigation) {
+  if (!navigation->IsInPrimaryMainFrame() || navigation->IsSameDocument() ||
+      !navigation->HasCommitted() || navigation->IsErrorPage()) {
+    return;
+  }
+
+  if (web_contents()->GetMainFrame()->GetVisibilityState() !=
+      content::PageVisibilityState::kVisible) {
+    return;
+  }
+
+  const GURL& url = web_contents()->GetLastCommittedURL();
+  if (!url.SchemeIsHTTPOrHTTPS()) {
+    return;
+  }
+
+  accuracy_service_->CheckAccuracyStatus(
+      url,
+      base::BindOnce(&AccuracyWebContentsObserver::OnAccuracyStatusObtained,
+                     weak_factory_.GetWeakPtr(), url));
+}
+
+void AccuracyWebContentsObserver::OnAccuracyStatusObtained(
+    const GURL& url,
+    AccuracyTipStatus result) {
+  if (result == AccuracyTipStatus::kNone)
+    return;
+
+  // We are not on this site anymore.
+  if (url != web_contents()->GetLastCommittedURL())
+    return;
+
+  accuracy_service_->MaybeShowAccuracyTip(web_contents());
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(AccuracyWebContentsObserver)
+}  // namespace accuracy_tips
\ No newline at end of file
diff --git a/components/accuracy_tips/accuracy_web_contents_observer.h b/components/accuracy_tips/accuracy_web_contents_observer.h
new file mode 100644
index 0000000..1ba91aae
--- /dev/null
+++ b/components/accuracy_tips/accuracy_web_contents_observer.h
@@ -0,0 +1,56 @@
+// Copyright 2021 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_ACCURACY_TIPS_ACCURACY_WEB_CONTENTS_OBSERVER_H_
+#define COMPONENTS_ACCURACY_TIPS_ACCURACY_WEB_CONTENTS_OBSERVER_H_
+
+#include "base/callback_forward.h"
+#include "components/accuracy_tips/accuracy_service.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+#include "content/public/browser/visibility.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
+
+namespace accuracy_tips {
+
+// Observes navigations and triggers a warning if a visited site is determined
+// to be low-accuracy.
+class AccuracyWebContentsObserver
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<AccuracyWebContentsObserver> {
+ public:
+  static bool IsEnabled(content::WebContents* web_contents);
+
+  ~AccuracyWebContentsObserver() override;
+
+  AccuracyWebContentsObserver(const AccuracyWebContentsObserver&) = delete;
+  AccuracyWebContentsObserver& operator=(const AccuracyWebContentsObserver&) =
+      delete;
+
+  // content::WebContentsObserver:
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+ private:
+  // Callback handler for accuracy result from AccuracyService.
+  void OnAccuracyStatusObtained(const GURL& url, AccuracyTipStatus result);
+
+  friend class content::WebContentsUserData<AccuracyWebContentsObserver>;
+
+  AccuracyWebContentsObserver(content::WebContents* web_contents,
+                              AccuracyService* accuracy_service);
+
+  AccuracyService* accuracy_service_;
+
+  base::WeakPtrFactory<AccuracyWebContentsObserver> weak_factory_{this};
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+}  // namespace accuracy_tips
+#endif  // COMPONENTS_ACCURACY_TIPS_ACCURACY_WEB_CONTENTS_OBSERVER_H_
diff --git a/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc b/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc
new file mode 100644
index 0000000..15216997
--- /dev/null
+++ b/components/accuracy_tips/accuracy_web_contents_observer_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright 2021 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/accuracy_tips/accuracy_web_contents_observer.h"
+#include <memory>
+
+#include "base/test/bind.h"
+#include "base/test/mock_callback.h"
+#include "components/accuracy_tips/accuracy_service.h"
+#include "components/accuracy_tips/accuracy_tip_status.h"
+#include "components/accuracy_tips/features.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::Mock;
+using AccuracyCheckCallback =
+    accuracy_tips::AccuracyService::AccuracyCheckCallback;
+
+namespace accuracy_tips {
+namespace {
+// Helpers to invoke callback on mocked function.
+void ReturnNone(const GURL&, AccuracyCheckCallback callback) {
+  std::move(callback).Run(AccuracyTipStatus::kNone);
+}
+void ReturnIsMisinformation(const GURL&, AccuracyCheckCallback callback) {
+  std::move(callback).Run(AccuracyTipStatus::kMisinformation);
+}
+}  // namespace
+
+class MockAccuracyService : public AccuracyService {
+ public:
+  MockAccuracyService() : AccuracyService(nullptr) {}
+  MOCK_METHOD2(CheckAccuracyStatus, void(const GURL&, AccuracyCheckCallback));
+  MOCK_METHOD1(MaybeShowAccuracyTip, void(content::WebContents*));
+};
+
+class AccuracyWebContentsObserverTest
+    : public content::RenderViewHostTestHarness {
+ protected:
+  AccuracyWebContentsObserverTest() = default;
+
+  void SetUp() override {
+    content::RenderViewHostTestHarness::SetUp();
+    service_ = std::make_unique<testing::StrictMock<MockAccuracyService>>();
+  }
+
+  MockAccuracyService* service() { return service_.get(); }
+
+ private:
+  std::unique_ptr<testing::StrictMock<MockAccuracyService>> service_;
+};
+
+TEST_F(AccuracyWebContentsObserverTest, CheckServiceOnNavigationToRandomSite) {
+  AccuracyWebContentsObserver::CreateForWebContents(web_contents(), service());
+  EXPECT_CALL(*service(), CheckAccuracyStatus(GURL("https://example.com"), _))
+      .WillOnce(Invoke(&ReturnNone));
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("https://example.com"));
+}
+
+TEST_F(AccuracyWebContentsObserverTest, CheckServiceOnNavigationToBadSite) {
+  AccuracyWebContentsObserver::CreateForWebContents(web_contents(), service());
+  EXPECT_CALL(*service(), CheckAccuracyStatus(GURL("https://badurl.com"), _))
+      .WillOnce(Invoke(&ReturnIsMisinformation));
+  EXPECT_CALL(*service(), MaybeShowAccuracyTip(web_contents()));
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("https://badurl.com"));
+}
+
+TEST_F(AccuracyWebContentsObserverTest, CheckServiceAndNavigationBeforeResult) {
+  AccuracyWebContentsObserver::CreateForWebContents(web_contents(), service());
+  // Capture callback for first navigation.
+  AccuracyCheckCallback callback;
+  EXPECT_CALL(*service(), CheckAccuracyStatus(GURL("https://badurl.com"), _))
+      .WillOnce(Invoke([&](const GURL&, AccuracyCheckCallback cb) {
+        callback = std::move(cb);
+      }));
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("https://badurl.com"));
+  Mock::VerifyAndClearExpectations(service());
+
+  // Navigate to a different site.
+  EXPECT_CALL(*service(), CheckAccuracyStatus(GURL("https://example.com"), _))
+      .WillOnce(Invoke(&ReturnNone));
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("https://example.com"));
+
+  // Verify that there is no call to MaybeShowAccuracyTip if callback is invoked
+  // after navigation to a different site.
+  std::move(callback).Run(AccuracyTipStatus::kMisinformation);
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(AccuracyWebContentsObserverTest, CheckServiceAndDestroyBeforeResult) {
+  AccuracyWebContentsObserver::CreateForWebContents(web_contents(), service());
+  AccuracyCheckCallback callback;
+  EXPECT_CALL(*service(), CheckAccuracyStatus(GURL("https://badurl.com"), _))
+      .WillOnce(Invoke([&](const GURL&, AccuracyCheckCallback cb) {
+        callback = std::move(cb);
+      }));
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(
+      web_contents(), GURL("https://badurl.com"));
+
+  // Invoke callback after webcontents is destroyed.
+  DeleteContents();
+  std::move(callback).Run(AccuracyTipStatus::kMisinformation);
+}
+
+}  // namespace accuracy_tips
\ No newline at end of file
diff --git a/components/accuracy_tips/features.cc b/components/accuracy_tips/features.cc
new file mode 100644
index 0000000..1c7e4b3f
--- /dev/null
+++ b/components/accuracy_tips/features.cc
@@ -0,0 +1,18 @@
+// Copyright 2021 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/accuracy_tips/features.h"
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+namespace accuracy_tips {
+
+const base::Feature kAccuracyTipsFeature{"AccuracyTips",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::FeatureParam<std::string> kSampleUrl{&kAccuracyTipsFeature,
+                                                 "sampleUrl", ""};
+
+}  // namespace accuracy_tips
\ No newline at end of file
diff --git a/components/accuracy_tips/features.h b/components/accuracy_tips/features.h
new file mode 100644
index 0000000..c121992
--- /dev/null
+++ b/components/accuracy_tips/features.h
@@ -0,0 +1,21 @@
+// Copyright 2021 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_ACCURACY_TIPS_FEATURES_H_
+#define COMPONENTS_ACCURACY_TIPS_FEATURES_H_
+
+#include "base/metrics/field_trial_params.h"
+
+namespace base {
+struct Feature;
+}  // namespace base
+
+namespace accuracy_tips {
+
+extern const base::Feature kAccuracyTipsFeature;
+extern const base::FeatureParam<std::string> kSampleUrl;
+
+}  // namespace accuracy_tips
+
+#endif  // COMPONENTS_ACCURACY_TIPS_FEATURES_H_
\ No newline at end of file
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
index c226624..915fa45 100644
--- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
+++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
@@ -157,6 +157,11 @@
   return true;
 }
 
+bool AutofillSaveUpdateAddressProfileDelegateIOS::EqualsDelegate(
+    infobars::InfoBarDelegate* delegate) const {
+  return delegate->GetIdentifier() == GetIdentifier();
+}
+
 int AutofillSaveUpdateAddressProfileDelegateIOS::GetIconId() const {
   // TODO(crbug.com/1167062): Replace with proper icon.
   return IDR_INFOBAR_AUTOFILL_CC;
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
index 4df0ee5..0f83f94 100644
--- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
+++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
@@ -81,6 +81,7 @@
   std::u16string GetButtonLabel(InfoBarButton button) const override;
   bool Accept() override;
   bool Cancel() override;
+  bool EqualsDelegate(infobars::InfoBarDelegate* delegate) const override;
 
  private:
   // Fires the |address_profile_save_prompt_callback_| callback.
diff --git a/components/autofill/core/browser/data_model/autofill_profile.cc b/components/autofill/core/browser/data_model/autofill_profile.cc
index b15114e..adf7569 100644
--- a/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -455,6 +455,13 @@
   }
 
   for (ServerFieldType type : types) {
+    // If the value is empty, the verification status can be ambiguous because
+    // the value could be either build from its empty child nodes or parsed
+    // from its parent. Therefore, it should not be considered when evaluating
+    // the similarity of two profiles.
+    if (profile.GetRawInfo(type).empty())
+      continue;
+
     if (structured_address::IsLessSignificantVerificationStatus(
             GetVerificationStatus(type), profile.GetVerificationStatus(type))) {
       return -1;
@@ -485,6 +492,13 @@
     }
 
     for (ServerFieldType type : types) {
+      // If the value is empty, the verification status can be ambiguous because
+      // the value could be either build from its empty child nodes or parsed
+      // from its parent. Therefore, it should not be considered when evaluating
+      // the similarity of two profiles.
+      if (profile.GetRawInfo(type).empty())
+        continue;
+
       if (structured_address::IsLessSignificantVerificationStatus(
               GetVerificationStatus(type),
               profile.GetVerificationStatus(type))) {
diff --git a/components/breadcrumbs/core/breadcrumb_manager_keyed_service.h b/components/breadcrumbs/core/breadcrumb_manager_keyed_service.h
index 892192b6..5fbbf54 100644
--- a/components/breadcrumbs/core/breadcrumb_manager_keyed_service.h
+++ b/components/breadcrumbs/core/breadcrumb_manager_keyed_service.h
@@ -22,6 +22,9 @@
 class BreadcrumbManagerKeyedService : public KeyedService {
  public:
   explicit BreadcrumbManagerKeyedService(bool is_off_the_record);
+  BreadcrumbManagerKeyedService(const BreadcrumbManagerKeyedService&) = delete;
+  BreadcrumbManagerKeyedService& operator=(
+      const BreadcrumbManagerKeyedService&) = delete;
   ~BreadcrumbManagerKeyedService() override;
 
   // Logs a breadcrumb |event| associated with the browser. Prepends the
@@ -70,8 +73,6 @@
   // The current BreadcrumbPersistentStorageManager persisting events logged to
   // |breadcrumb_manager_|, set by StartPersisting. May be null.
   BreadcrumbPersistentStorageManager* persistent_storage_manager_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(BreadcrumbManagerKeyedService);
 };
 
 }  // namespace breadcrumbs
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
index 7253d28..c767ca1 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> word toegelaat}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> word toegelaat}}</translation>
 <translation id="2434158240863470628">Aflaai is voltooi <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Kennisgewings</translation>
+<translation id="2485422356828889247">Deïnstalleer</translation>
 <translation id="2490684707762498678">Bestuur deur <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Hulp en terugvoer</translation>
 <translation id="2501278716633472235">Gaan terug</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresse</translation>
 <translation id="2910701580606108292">Vra voordat werwe toegelaat word om beskermde inhoud te speel</translation>
 <translation id="2913331724188855103">Laat werwe toe om webkoekiedata te stoor en te lees (aanbeveel)</translation>
+<translation id="2932883381142163287">Gee misbruik aan</translation>
 <translation id="2968755619301702150">Sertifikaatbekyker</translation>
 <translation id="300526633675317032">Dit sal al <ph name="SIZE_IN_KB" /> se webwerfberging uitvee.</translation>
 <translation id="3008272652534848354">Stel toestemmings terug</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
index 8f85650..800731c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />፣ <ph name="PERMISSION_2" />፣ እና <ph name="NUM_MORE" /> ተጨማሪ ተፈቅደዋል}one{<ph name="PERMISSION_1" />፣ <ph name="PERMISSION_2" /> እና <ph name="NUM_MORE" /> ተጨማሪ ተፈቅደዋል}other{<ph name="PERMISSION_1" />፣ <ph name="PERMISSION_2" /> እና <ph name="NUM_MORE" /> ተጨማሪ ተፈቅደዋል}}</translation>
 <translation id="2434158240863470628">ማውረድ ተጠናቅቋል <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">ማስታወቂያዎች</translation>
+<translation id="2485422356828889247">አራግፍ</translation>
 <translation id="2490684707762498678">በ<ph name="APP_NAME" /> የሚተዳደር ነው</translation>
 <translation id="2498359688066513246">እገዛ እና ግብረመልስ</translation>
 <translation id="2501278716633472235">ወደ ኋላ ተመለስ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">አድራሻዎች</translation>
 <translation id="2910701580606108292">ጣቢያዎች ጥበቃ የሚደረግለትን ይዘትን እንዲያጫውቱ ከመፍቀድ በፊት ጠይቅ</translation>
 <translation id="2913331724188855103">ጣቢያዎች የኩኪ ውሂብ እንዲያስቀምጡ እና እንዲያነቡ ይፍቀዱ (የሚመከር)</translation>
+<translation id="2932883381142163287">የአላግባብ መጠቀምን ሪፖርት ያድርጉ</translation>
 <translation id="2968755619301702150">የእውቅና ማረጋገጫ መመልከቻ</translation>
 <translation id="300526633675317032">ይህ ሁሉንም <ph name="SIZE_IN_KB" /> የድር ጣቢያ ማከማቻ ያጸዳል።</translation>
 <translation id="3008272652534848354">ፈቃዶችን ዳግም ያቀናብሩ</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
index 40752b6..b9dc0be 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذن واحد (<ph name="NUM_MORE" />) آخر.}zero{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر.}two{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذنَين (<ph name="NUM_MORE" />) آخرَين.}few{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> أذونات أخرى.}many{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذنًا آخر.}other{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر.}}</translation>
 <translation id="2434158240863470628">اكتمل التنزيل <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">الإشعارات</translation>
+<translation id="2485422356828889247">إزالة التثبيت</translation>
 <translation id="2490684707762498678">تتم إدارتها من خلال <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">المساعدة والتعليقات</translation>
 <translation id="2501278716633472235">الرجوع</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">العناوين</translation>
 <translation id="2910701580606108292">السؤال قبل السماح للمواقع الإلكترونية بتشغيل المحتوى المحمي</translation>
 <translation id="2913331724188855103">ألسماح للمواقع الإلكترونية بحفظ بيانات ملفات تعريف الارتباط وقراءتها (يُنصح به)</translation>
+<translation id="2932883381142163287">الإبلاغ عن إساءة الاستخدام</translation>
 <translation id="2968755619301702150">عارض الشهادات</translation>
 <translation id="300526633675317032">سيؤدي هذا إلى محو مساحة التخزين البالغة <ph name="SIZE_IN_KB" /> بأكملها من مساحة تخزين المواقع الإلكترونية.</translation>
 <translation id="3008272652534848354">إعادة ضبط الأذونات</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
index 88b384c..064a4b8 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰু <ph name="NUM_MORE" /> টাৰ অনুমতি দিয়া আছে}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰু <ph name="NUM_MORE" /> টাৰ অনুমতি দিয়া আছে}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰু <ph name="NUM_MORE" /> টাৰ অনুমতি দিয়া আছে}}</translation>
 <translation id="2434158240863470628">ডাউনল’ড সম্পূর্ণ হৈছে <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">জাননী</translation>
+<translation id="2485422356828889247">আনইনষ্টল কৰক</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" />এ পৰিচালনা কৰে</translation>
 <translation id="2498359688066513246">সহায় আৰু মতামত</translation>
 <translation id="2501278716633472235">উভতি যাওক</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ঠিকনা</translation>
 <translation id="2910701580606108292">ছাইটক প্রতিবন্ধিত সমল প্লে' কৰিব দিয়াৰ আগত সোধক</translation>
 <translation id="2913331724188855103">ছাইটসমূহক কুকি ডেটা ছেভ কৰিবলৈ আৰু পঢ়িবলৈ অনুমতি দিয়ক (আমি চুপাৰিছ কৰোঁ)</translation>
+<translation id="2932883381142163287">দুৰ্ব্যৱহাৰৰ অভিযোগ দিয়ক</translation>
 <translation id="2968755619301702150">প্ৰমাণপত্ৰ ভিউৱাৰ</translation>
 <translation id="300526633675317032">এইটোৱে ৱেবছাইটৰ ষ্ট’ৰেজৰ সম্পূৰ্ণ <ph name="SIZE_IN_KB" /> মচি পেলাব।</translation>
 <translation id="3008272652534848354">অনুমতি ৰিছেট কৰক</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
index 712624d..5f0d5a4 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> və daha <ph name="NUM_MORE" /> üçün icazə verilib}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> və daha <ph name="NUM_MORE" /> üçün icazə verilib}}</translation>
 <translation id="2434158240863470628">Endirmə tamamlandı <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Bildirişlər</translation>
+<translation id="2485422356828889247">Sistemdən silin</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> tərəfindən idarə edilir</translation>
 <translation id="2498359688066513246">Yardım və geri əlaqə</translation>
 <translation id="2501278716633472235">Geri qayıdın</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Ünvanlar</translation>
 <translation id="2910701580606108292">Saytlar qorunan kontenti göstərmədən öncə icazə tələb edilsin</translation>
 <translation id="2913331724188855103">Saytlara kuki datanı saxlamağa və oxumağa imkan verir (tövsiyə olunur)</translation>
+<translation id="2932883381142163287">Sui-istifadəni xəbər verin</translation>
 <translation id="2968755619301702150">Sertifikat izləyici</translation>
 <translation id="300526633675317032">Bu, veb sayt yaddaşının <ph name="SIZE_IN_KB" /> hissəsini siləcək</translation>
 <translation id="3008272652534848354">İcazələri sıfırlayın</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
index abeccc5a..78f7a9f6 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> і яшчэ <ph name="NUM_MORE" />}one{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> і яшчэ <ph name="NUM_MORE" />}few{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> і яшчэ <ph name="NUM_MORE" />}many{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> і яшчэ <ph name="NUM_MORE" />}other{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> і яшчэ <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Спампоўванне завершана <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Апавяшчэнні</translation>
+<translation id="2485422356828889247">Выдаліць</translation>
 <translation id="2490684707762498678">Пад кіраваннем праграмы "<ph name="APP_NAME" />"</translation>
 <translation id="2498359688066513246">Даведка і водгукі</translation>
 <translation id="2501278716633472235">Назад</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Адрасы</translation>
 <translation id="2910701580606108292">Пытаць, перш чым дазволіць прайграванне абароненага змесціва на сайтах</translation>
 <translation id="2913331724188855103">Дазволіць сайтам захоўваць і чытаць даныя файлаў cookie (рэкамендуецца)</translation>
+<translation id="2932883381142163287">Паскардзіцца</translation>
 <translation id="2968755619301702150">Звесткі пра сертыфікат</translation>
 <translation id="300526633675317032">Гэта вызваліць <ph name="SIZE_IN_KB" /> у сховішчы вэб-сайтаў.</translation>
 <translation id="3008272652534848354">Скінуць дазволы</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
index 389422e..a882c0b7 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Достъпът до <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" /> е разрешен}other{Достъпът до <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" /> е разрешен}}</translation>
 <translation id="2434158240863470628">Изтеглянето завърши <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Известия</translation>
+<translation id="2485422356828889247">Деинсталиране</translation>
 <translation id="2490684707762498678">Управляват се от <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Помощ и отзиви</translation>
 <translation id="2501278716633472235">Назад</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Адреси</translation>
 <translation id="2910701580606108292">Запитване преди разрешаване на сайтовете да възпроизвеждат защитено съдържание</translation>
 <translation id="2913331724188855103">Разрешаване на сайтовете да запазват „бисквитки“ и да четат данни от такива (препоръчително)</translation>
+<translation id="2932883381142163287">Подаване на сигнал за злоупотреба</translation>
 <translation id="2968755619301702150">Визуализатор на сертификатите</translation>
 <translation id="300526633675317032">Така ще се изчистят всички съхранявани данни от уебсайтове (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Нулиране на разрешенията</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
index 65d94995..e992bc4 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সুবিধা ব্যবহারের অনুমতি দেওয়া হয়েছে}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সুবিধা ব্যবহারের অনুমতি দেওয়া হয়েছে}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সুবিধা ব্যবহারের অনুমতি দেওয়া হয়েছে}}</translation>
 <translation id="2434158240863470628"><ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /> ডাউনলোড সম্পূর্ণ হয়েছে</translation>
 <translation id="2482878487686419369">বিজ্ঞপ্তিগুলি</translation>
+<translation id="2485422356828889247">আনইনস্টল</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ম্যানেজ করে</translation>
 <translation id="2498359688066513246">সহায়তা ও প্রতিবার্তা</translation>
 <translation id="2501278716633472235">ফিরে যান</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ঠিকানা</translation>
 <translation id="2910701580606108292">কোনও সাইটে সুরক্ষিত কন্টেন্ট চালু হওয়ার আগে আমায় জিজ্ঞেস করা হোক</translation>
 <translation id="2913331724188855103">সাইটগুলিকে কুকি ডেটা পড়ার এবং সংরক্ষণ করার অনুমতি দিন (প্রস্তাবিত)</translation>
+<translation id="2932883381142163287">আপত্তিজনক হিসাবে অভিযোগ করুন</translation>
 <translation id="2968755619301702150">সার্টিফিকেট প্রদর্শনকারী</translation>
 <translation id="300526633675317032">এটা ওয়েবসাইট স্টোরেজের <ph name="SIZE_IN_KB" />-এর পুরোটা সাফ করবে।</translation>
 <translation id="3008272652534848354">অনুমতি রিসেট করুন</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
index fd434216..ab1af32 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Preuzimanje je završeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Obavještenja</translation>
+<translation id="2485422356828889247">Deinstaliraj</translation>
 <translation id="2490684707762498678">Upravlja aplikacija <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Pomoć i povr. inf.</translation>
 <translation id="2501278716633472235">Nazad</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adrese</translation>
 <translation id="2910701580606108292">Web lokacije moraju tražiti dozvolu za reprodukciju zaštićenog sadržaja</translation>
 <translation id="2913331724188855103">Omogućite web lokacijama da sačuvaju i čitaju podatke o kolačićima (preporučeno)</translation>
+<translation id="2932883381142163287">Prijavite zloupotrebu</translation>
 <translation id="2968755619301702150">Preglednik certifikata</translation>
 <translation id="300526633675317032">Time će se izbrisati cijela pohrana web-lokacije veličine <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Poništi dopuštenja</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
index 64b7a67..99e8f60 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{S'han permès <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}other{S'han permès <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}}</translation>
 <translation id="2434158240863470628">S'ha completat la baixada <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificacions</translation>
+<translation id="2485422356828889247">Desinstal·la</translation>
 <translation id="2490684707762498678">Gestionades per <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ajuda i suggeriments </translation>
 <translation id="2501278716633472235">Torna</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adreces</translation>
 <translation id="2910701580606108292">Pregunta abans de permetre que els llocs web reprodueixin contingut protegit</translation>
 <translation id="2913331724188855103">Permet que els llocs web desin i llegeixin les dades de les galetes (opció recomanada)</translation>
+<translation id="2932883381142163287">Informa d'un ús abusiu</translation>
 <translation id="2968755619301702150">Lector de certificats</translation>
 <translation id="300526633675317032">Amb aquesta acció s'esborraran <ph name="SIZE_IN_KB" /> d'emmagatzematge del lloc web.</translation>
 <translation id="3008272652534848354">Restableix els permisos</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
index 1014301c..55bc54e 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}few{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}many{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}other{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}}</translation>
 <translation id="2434158240863470628">Stažení bylo dokončeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Oznámení</translation>
+<translation id="2485422356828889247">Odinstalovat</translation>
 <translation id="2490684707762498678">Spravováno aplikací <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Nápověda a zpětná vazba</translation>
 <translation id="2501278716633472235">Zpět</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresy</translation>
 <translation id="2910701580606108292">Před povolením spuštění chráněného obsahu na webu se zeptat</translation>
 <translation id="2913331724188855103">Povolit webům ukládat a číst data souborů cookie (doporučeno)</translation>
+<translation id="2932883381142163287">Nahlásit zneužití</translation>
 <translation id="2968755619301702150">Prohlížeč certifikátů</translation>
 <translation id="300526633675317032">Tímto vymažete celé úložiště webů (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Resetovat oprávnění</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
index bccf021..4012497 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere er tilladt}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere er tilladt}}</translation>
 <translation id="2434158240863470628">Downloaden er fuldført <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notifikationer</translation>
+<translation id="2485422356828889247">Afinstaller</translation>
 <translation id="2490684707762498678">Administreret af <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Hjælp og feedback</translation>
 <translation id="2501278716633472235">Gå tilbage</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresser</translation>
 <translation id="2910701580606108292">Spørg, før websites begynder at afspille beskyttet indhold</translation>
 <translation id="2913331724188855103">Tillad, at websites gemmer og læser cookiedata (anbefales)</translation>
+<translation id="2932883381142163287">Rapportér misbrug</translation>
 <translation id="2968755619301702150">Certifikatfremviser</translation>
 <translation id="300526633675317032">Dette rydder alle <ph name="SIZE_IN_KB" /> i websitelagerpladsen.</translation>
 <translation id="3008272652534848354">Nulstil tilladelser</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
index 0be6da7..88a62d9a 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere zugelassen}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere zugelassen}}</translation>
 <translation id="2434158240863470628">Download abgeschlossen <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Benachrichtigungen</translation>
+<translation id="2485422356828889247">Deinstallieren</translation>
 <translation id="2490684707762498678">Über <ph name="APP_NAME" /> verwaltet</translation>
 <translation id="2498359688066513246">Hilfe &amp; Feedback</translation>
 <translation id="2501278716633472235">Zurück</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adressen</translation>
 <translation id="2910701580606108292">Fragen, bevor die Wiedergabe geschützter Inhalte auf Websites zugelassen wird</translation>
 <translation id="2913331724188855103">Websites dürfen Cookiedaten speichern und lesen (empfohlen)</translation>
+<translation id="2932883381142163287">Missbrauch melden</translation>
 <translation id="2968755619301702150">Zertifikats-Viewer</translation>
 <translation id="300526633675317032">Der gesamte Websitespeicher (<ph name="SIZE_IN_KB" />) wird gelöscht.</translation>
 <translation id="3008272652534848354">Berechtigungen zurücksetzen</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
index 12865fd..051c248 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Οι άδειες <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη επιτράπηκαν.}other{Οι άδειες <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη επιτράπηκαν.}}</translation>
 <translation id="2434158240863470628">Η λήψη ολοκληρώθηκε <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Ειδοποιήσεις</translation>
+<translation id="2485422356828889247">Απεγκατάσταση</translation>
 <translation id="2490684707762498678">Διαχειριζόμενες από την εφαρμογή <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Βοήθεια και σχόλια</translation>
 <translation id="2501278716633472235">Επιστροφή</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Διευθύνσεις</translation>
 <translation id="2910701580606108292">Να γίνεται ερώτηση προτού επιτραπεί στους ιστοτόπους η αναπαραγωγή προστατευόμενου περιεχομένου</translation>
 <translation id="2913331724188855103">Να επιτρέπεται στους ιστότοπους η αποθήκευση και η ανάγνωση δεδομένων cookie (συνιστάται)</translation>
+<translation id="2932883381142163287">Αναφορά κατάχρησης</translation>
 <translation id="2968755619301702150">Πρόγρ. προβολής πιστοποιητικού</translation>
 <translation id="300526633675317032">Αυτό θα διαγράψει και τα <ph name="SIZE_IN_KB" /> του αποθηκευτικού χώρου ιστοτόπων.</translation>
 <translation id="3008272652534848354">Επαναφορά αδειών</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
index 48092fd..c88ba23e 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> and <ph name="NUM_MORE" /> more allowed}}</translation>
 <translation id="2434158240863470628">Download complete <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notifications</translation>
+<translation id="2485422356828889247">Uninstall</translation>
 <translation id="2490684707762498678">Managed by <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Help &amp; feedback</translation>
 <translation id="2501278716633472235">Go back</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Addresses</translation>
 <translation id="2910701580606108292">Ask before allowing sites to play protected content</translation>
 <translation id="2913331724188855103">Allow sites to save and read cookie data (recommended)</translation>
+<translation id="2932883381142163287">Report abuse</translation>
 <translation id="2968755619301702150">Certificate viewer</translation>
 <translation id="300526633675317032">This will clear all <ph name="SIZE_IN_KB" /> of website storage.</translation>
 <translation id="3008272652534848354">Reset permissions</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
index 1431966..67ca34b 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Permitidos: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}other{Permitidos: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}}</translation>
 <translation id="2434158240863470628">Se completó la descarga <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificaciones</translation>
+<translation id="2485422356828889247">Desinstalación</translation>
 <translation id="2490684707762498678">Administradas por <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ayuda y comentarios</translation>
 <translation id="2501278716633472235">Ir atrás</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Direcciones</translation>
 <translation id="2910701580606108292">Preguntar antes de permitir que los sitios reproduzcan contenido protegido</translation>
 <translation id="2913331724188855103">Permitir que todos los sitios guarden y lean datos de cookies (recomendado)</translation>
+<translation id="2932883381142163287">Informar sobre abusos</translation>
 <translation id="2968755619301702150">Visualizador de certificados</translation>
 <translation id="300526633675317032">Se borrarán <ph name="SIZE_IN_KB" /> del almacenamiento del sitio web.</translation>
 <translation id="3008272652534848354">Restablecer permisos</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
index e9d04baf..fd98aac 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más permitidos}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más permitidos}}</translation>
 <translation id="2434158240863470628">Descarga finalizada <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificaciones</translation>
+<translation id="2485422356828889247">Desinstalar</translation>
 <translation id="2490684707762498678">Gestionadas por <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ayuda y comentarios</translation>
 <translation id="2501278716633472235">Volver</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Direcciones</translation>
 <translation id="2910701580606108292">Preguntar antes de permitir que los sitios reproduzcan contenido protegido</translation>
 <translation id="2913331724188855103">Permitir que los sitios guarden y lean datos de cookies (recomendado)</translation>
+<translation id="2932883381142163287">Notificar uso inadecuado</translation>
 <translation id="2968755619301702150">Visor de certificados</translation>
 <translation id="300526633675317032">Se borrarán los <ph name="SIZE_IN_KB" /> de almacenamiento del sitio web.</translation>
 <translation id="3008272652534848354">Borrar permisos</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
index dc03025..5f03a9f 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" /> on lubatud}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" /> on lubatud}}</translation>
 <translation id="2434158240863470628">Allalaadimine jõudis lõpule: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Märguanded</translation>
+<translation id="2485422356828889247">Desinstalli</translation>
 <translation id="2490684707762498678">Haldab <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Abi ja tagasiside</translation>
 <translation id="2501278716633472235">Mine tagasi</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Aadressid</translation>
 <translation id="2910701580606108292">Küsi enne saitidel kaitstud sisu esitamise lubamist</translation>
 <translation id="2913331724188855103">Lubab saitidel salvestada küpsiseid ja lugeda küpsiste andmeid (soovitatav)</translation>
+<translation id="2932883381142163287">Teata väärkasutusest</translation>
 <translation id="2968755619301702150">Sertifikaadikuvaja</translation>
 <translation id="300526633675317032">See tühjendab veebisaidi salvestusruumi mahuga <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Lähtesta load</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
index 9f3eb98..3ed21c1 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Baimena eman zaie hauei: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}other{Baimena eman zaie hauei: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Deskargatu da <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Jakinarazpenak</translation>
+<translation id="2485422356828889247">Desinstalatu</translation>
 <translation id="2490684707762498678">Kudeatzailea: <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Laguntza eta iritziak</translation>
 <translation id="2501278716633472235">Egin atzera</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Helbideak</translation>
 <translation id="2910701580606108292">Webguneei eduki babestua erreproduzitzeko baimena eman aurretik, eskatu onespena</translation>
 <translation id="2913331724188855103">Baimendu webguneei cookieen datuak gordetzea eta irakurtzea (gomendatua)</translation>
+<translation id="2932883381142163287">Eman erabilera okerren berri</translation>
 <translation id="2968755619301702150">Ziurtagiri-ikustailea</translation>
 <translation id="300526633675317032"><ph name="SIZE_IN_KB" /> ezabatuko dira webguneen datuetatik.</translation>
 <translation id="3008272652534848354">Berrezarri baimenak</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
index be80a5c..e04647d 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}one{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}}</translation>
 <translation id="2434158240863470628">بارگیری کامل شد <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">اعلان‌ها</translation>
+<translation id="2485422356828889247">حذف نصب</translation>
 <translation id="2490684707762498678">تحت مدیریت <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">راهنمایی و بازخورد</translation>
 <translation id="2501278716633472235">بازگشت</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">آدرس‌ها</translation>
 <translation id="2910701580606108292">قبل از اجازه دادن به سایت‌ها برای پخش محتوای محافظت‌شده سؤال شود</translation>
 <translation id="2913331724188855103">سایت‌ها مجاز به ذخیره و خواندن داده‌های کوکی باشند (توصیه می‌شود)</translation>
+<translation id="2932883381142163287">گزارش سوءاستفاده</translation>
 <translation id="2968755619301702150">بیننده گواهی</translation>
 <translation id="300526633675317032">این کار کل <ph name="SIZE_IN_KB" /> فضای ذخیره‌سازی وب‌سایت را پاک می‌کند.</translation>
 <translation id="3008272652534848354">بازنشانی مجوزها</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
index 7ff3c25..7cc8d9b 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta sallittu}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta sallittu}}</translation>
 <translation id="2434158240863470628">Lataus valmis <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Ilmoitukset</translation>
+<translation id="2485422356828889247">Poista</translation>
 <translation id="2490684707762498678">Ylläpitäjä: <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ohjeet ja palaute</translation>
 <translation id="2501278716633472235">Takaisin</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Osoitteet</translation>
 <translation id="2910701580606108292">Kysy, saavatko sivustot toistaa suojattua sisältöä</translation>
 <translation id="2913331724188855103">Salli sivustojen tallentaa ja lukea evästetietoja (suositus)</translation>
+<translation id="2932883381142163287">Ilmoita väärinkäytöstä</translation>
 <translation id="2968755619301702150">Varmennetiedot</translation>
 <translation id="300526633675317032">Tämä tyhjentää yhteensä <ph name="SIZE_IN_KB" /> tallennettuja sivustotietoja.</translation>
 <translation id="3008272652534848354">Nollaa käyttöoikeudet</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
index ebe41bd..158bc7b 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}one{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}other{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}}</translation>
 <translation id="2434158240863470628">Tapos nang mag-download <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Mga Abiso</translation>
+<translation id="2485422356828889247">I-uninstall</translation>
 <translation id="2490684707762498678">Pinapamahalaan ng <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Tulong at feedback</translation>
 <translation id="2501278716633472235">Bumalik</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Mga Address</translation>
 <translation id="2910701580606108292">Magtanong bago payagan ang mga site na mag-play ng pinoprotektahang content</translation>
 <translation id="2913331724188855103">Payagan ang mga site na mag-save at magbasa ng data ng cookie (inirerekomenda)</translation>
+<translation id="2932883381142163287">I-ulat ang pang-aabuso</translation>
 <translation id="2968755619301702150">Viewer ng certificate</translation>
 <translation id="300526633675317032">Iki-clear nito ang lahat ng <ph name="SIZE_IN_KB" /> ng storage ng website.</translation>
 <translation id="3008272652534848354">I-reset ang mga pahintulot</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
index 21da2c36..8ef20bb 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre accordées}one{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre accordées}other{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autres accordées}}</translation>
 <translation id="2434158240863470628">Téléchargement terminé <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notifications</translation>
+<translation id="2485422356828889247">Désinstaller</translation>
 <translation id="2490684707762498678">Les notifications sont gérées par <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Aide et commentaires</translation>
 <translation id="2501278716633472235">Retour</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresses</translation>
 <translation id="2910701580606108292">Demander avant d'autoriser les sites à lire du contenu protégé</translation>
 <translation id="2913331724188855103">Autoriser les sites à enregistrer et à lire les données des témoins (recommandé)</translation>
+<translation id="2932883381142163287">Signaler un abus</translation>
 <translation id="2968755619301702150">Lecteur de certificats</translation>
 <translation id="300526633675317032">Cette action entraînera la suppression de l'ensemble des <ph name="SIZE_IN_KB" /> d'espace de stockage des sites Web.</translation>
 <translation id="3008272652534848354">Réinitialiser les autorisations</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
index 8ccef9a..586fcc2 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}one{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}other{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}}</translation>
 <translation id="2434158240863470628">Téléchargement terminé <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notifications</translation>
+<translation id="2485422356828889247">Désinstaller</translation>
 <translation id="2490684707762498678">Géré par <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Aide et commentaires</translation>
 <translation id="2501278716633472235">Retour</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresses</translation>
 <translation id="2910701580606108292">Demander avant d'autoriser les sites à lire les contenus protégés</translation>
 <translation id="2913331724188855103">Autoriser les sites à enregistrer et à lire les données des cookies (recommandé)</translation>
+<translation id="2932883381142163287">Signaler un abus</translation>
 <translation id="2968755619301702150">Lecteur de certificat</translation>
 <translation id="300526633675317032">Cette action aura pour effet de libérer l'espace de stockage utilisé pour les données de site (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Réinitialiser les autorisations</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
index 28b0d91..accfbf87 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis (permitidos)}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis (permitidos)}}</translation>
 <translation id="2434158240863470628">Completouse a descarga <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificacións</translation>
+<translation id="2485422356828889247">Desinstalar</translation>
 <translation id="2490684707762498678">Xestionadas por <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Axuda e comentarios</translation>
 <translation id="2501278716633472235">Ir atrás</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Enderezos</translation>
 <translation id="2910701580606108292">Preguntar antes de permitir que os sitios reproduzan contido protexido</translation>
 <translation id="2913331724188855103">Permitir que os sitios garden e lean datos de cookies (recomendado)</translation>
+<translation id="2932883381142163287">Informar de uso inadecuado</translation>
 <translation id="2968755619301702150">Visor de certificados</translation>
 <translation id="300526633675317032">Eliminaranse os <ph name="SIZE_IN_KB" /> de almacenamento do sitio web.</translation>
 <translation id="3008272652534848354">Restablecer permisos</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
index 161b6fce..f6d4401 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધુ <ph name="NUM_MORE" />ની મંજૂરી આપી}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધુ <ph name="NUM_MORE" />ની મંજૂરી આપી}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધુ <ph name="NUM_MORE" />ની મંજૂરી આપી}}</translation>
 <translation id="2434158240863470628">ડાઉનલોડ પૂર્ણ <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">નોટિફિકેશનો</translation>
+<translation id="2485422356828889247">અનઇન્સ્ટૉલ કરો</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> દ્વારા મેનેજ થયેલ</translation>
 <translation id="2498359688066513246">સહાય અને પ્રતિસાદ</translation>
 <translation id="2501278716633472235">પાછા જાઓ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">સરનામાંઓ</translation>
 <translation id="2910701580606108292">સાઇટને સંરક્ષિત કન્ટેન્ટ ચલાવવાની મંજૂરી આપતા પહેલાંં પૂછો</translation>
 <translation id="2913331724188855103">સાઇટને કૂકી ડેટા સાચવવા અને વાંચવાની મંજૂરી આપો (ભલામણ કરેલ)</translation>
+<translation id="2932883381142163287">દુરુપયોગ જણાવો</translation>
 <translation id="2968755619301702150">પ્રમાણપત્ર દર્શક</translation>
 <translation id="300526633675317032">આ <ph name="SIZE_IN_KB" /> નું બધું વેબસાઇટ સ્ટોરેજ સાફ કરશે.</translation>
 <translation id="3008272652534848354">પરવાનગીઓ રીસેટ કરો</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
index cad2534..2b201ee 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अन्य सुविधा को इस्तेमाल करने की अनुमति दी गई}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अन्य सुविधा को इस्तेमाल करने की अनुमति दी गई}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अन्य सुविधाओं को इस्तेमाल करने की अनुमति दी गई}}</translation>
 <translation id="2434158240863470628">डाउनलोड हो गया <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">सूचनाएं</translation>
+<translation id="2485422356828889247">विस्थापित करें</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> प्रबंधित करता है</translation>
 <translation id="2498359688066513246">सहायता और फ़ीडबैक</translation>
 <translation id="2501278716633472235">वापस जाएं</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">पते</translation>
 <translation id="2910701580606108292">साइटों को सुरक्षित सामग्री चलाने की अनुमति देने से पहले पूछें</translation>
 <translation id="2913331724188855103">साइटों को कुकी डेटा सेव करने और पढ़ने की अनुमति दें (सुझाए गए)</translation>
+<translation id="2932883381142163287">बुरे बर्ताव की शिकायत करें</translation>
 <translation id="2968755619301702150">प्रमाणपत्र व्यूअर</translation>
 <translation id="300526633675317032">इससे वेबसाइट की पूरी <ph name="SIZE_IN_KB" /> मेमोरी साफ़ हो जाएगी.</translation>
 <translation id="3008272652534848354">अनुमतियां रीसेट करें</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
index 54c564b..d0e5c84 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Preuzimanje je dovršeno: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Obavijesti</translation>
+<translation id="2485422356828889247">Deinstaliraj</translation>
 <translation id="2490684707762498678">Upravlja: <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Pomoć i povratne informacije</translation>
 <translation id="2501278716633472235">Natrag</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adrese</translation>
 <translation id="2910701580606108292">Web-lokacije moraju tražiti dopuštenje za reprodukciju zaštićenog sadržaja</translation>
 <translation id="2913331724188855103">Dopusti web-lokacijama da spremaju i čitaju podatke kolačića (preporučeno)</translation>
+<translation id="2932883381142163287">Prijavi zloupotrebu</translation>
 <translation id="2968755619301702150">Preglednik certifikata</translation>
 <translation id="300526633675317032">Time će se izbrisati cijela pohrana web-lokacije veličine <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Poništi dopuštenja</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
index bf49989..b5ecc37 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" /> engedélyezve}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" /> engedélyezve}}</translation>
 <translation id="2434158240863470628">Letöltés befejezve <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Értesítések</translation>
+<translation id="2485422356828889247">Eltávolítás</translation>
 <translation id="2490684707762498678">Kezelő: <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Súgó és visszajelzés</translation>
 <translation id="2501278716633472235">Visszalépés</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Címek</translation>
 <translation id="2910701580606108292">Kérdezzen rá, mielőtt engedélyezné a webhelyek számára védett tartalmak lejátszását</translation>
 <translation id="2913331724188855103">Cookie-adatok mentésének és olvasásának engedélyezése a webhelyeken (ajánlott)</translation>
+<translation id="2932883381142163287">Visszaélés bejelentése</translation>
 <translation id="2968755619301702150">Tanúsítványmegtekintő</translation>
 <translation id="300526633675317032">Ezzel törli a webhely teljes tárhelyét: <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Engedélyek visszavonása</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
index adbbffc9..88faf2ca 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Թույլատրված են՝ «<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» ու ևս <ph name="NUM_MORE" /> թույլտվություն}one{Թույլատրված են՝ «<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» ու ևս <ph name="NUM_MORE" /> թույլտվություն}other{Թույլատրված են՝ «<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» ու ևս <ph name="NUM_MORE" /> թույլտվություն}}</translation>
 <translation id="2434158240863470628">Ներբեռնումն ավարտված է՝ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Ծանուցումներ</translation>
+<translation id="2485422356828889247">Ապատեղադրել</translation>
 <translation id="2490684707762498678">Կառավարվում է <ph name="APP_NAME" /> հավելվածի կողմից</translation>
 <translation id="2498359688066513246">Օգնություն և հետադարձ կապ</translation>
 <translation id="2501278716633472235">Վերադառնալ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Հասցեներ</translation>
 <translation id="2910701580606108292">Պաշտպանված բովանդակություն նվագարկելու թույլտվություն հարցել</translation>
 <translation id="2913331724188855103">Թույլատրել կայքերին պահել և կարդալ քուքիների տվյալները (խորհուրդ է տրվում)</translation>
+<translation id="2932883381142163287">Հաղորդել չարաշահման մասին</translation>
 <translation id="2968755619301702150">Վկայագրերի դիտում</translation>
 <translation id="300526633675317032">Կազատվի կայքի օգտագործած <ph name="SIZE_IN_KB" /> տարածք:</translation>
 <translation id="3008272652534848354">Վերակայել թույլտվությունները</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
index ac88d11..66cc954 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya diizinkan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya diizinkan}}</translation>
 <translation id="2434158240863470628">Download selesai <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notifikasi</translation>
+<translation id="2485422356828889247">Uninstal</translation>
 <translation id="2490684707762498678">Dikelola oleh <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Bantuan &amp; masukan</translation>
 <translation id="2501278716633472235">Kembali</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Alamat</translation>
 <translation id="2910701580606108292">Tanyakan sebelum mengizinkan situs untuk memutar konten yang dilindungi</translation>
 <translation id="2913331724188855103">Izinkan situs untuk menyimpan dan membaca data cookie (disarankan)</translation>
+<translation id="2932883381142163287">Laporkan penyalahgunaan</translation>
 <translation id="2968755619301702150">Penampil sertifikat</translation>
 <translation id="300526633675317032">Ini akan menghapus seluruh penyimpanan situs web, sebesar <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Reset izin</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
index 6c3fb63..29b71fe 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}one{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}other{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}}</translation>
 <translation id="2434158240863470628">Niðurhali lokið <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Tilkynningar</translation>
+<translation id="2485422356828889247">Fjarlægja</translation>
 <translation id="2490684707762498678">Stýrt af <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Hjálp og ábendingar</translation>
 <translation id="2501278716633472235">Fara til baka</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Heimilisföng</translation>
 <translation id="2910701580606108292">Spyrja áður en vefsvæðum er veitt heimild til að spila varið efni</translation>
 <translation id="2913331724188855103">Leyfa vefsvæðum að vista og lesa fótsporagögn (ráðlagt)</translation>
+<translation id="2932883381142163287">Tilkynna misnotkun</translation>
 <translation id="2968755619301702150">Vottorðaskoðari</translation>
 <translation id="300526633675317032">Þetta mun losa alls um <ph name="SIZE_IN_KB" /> af geymslu vefsvæða.</translation>
 <translation id="3008272652534848354">Endurstilla heimildir</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
index 119570d..8bcd36c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}other{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Download completato: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notifiche</translation>
+<translation id="2485422356828889247">Disinstalla</translation>
 <translation id="2490684707762498678">Gestite da <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Guida e feedback</translation>
 <translation id="2501278716633472235">Indietro</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Indirizzi</translation>
 <translation id="2910701580606108292">Chiedi prima di consentire ai siti di riprodurre contenuti protetti</translation>
 <translation id="2913331724188855103">Consenti ai siti di salvare e leggere i dati dei cookie (opzione consigliata)</translation>
+<translation id="2932883381142163287">Segnala abuso</translation>
 <translation id="2968755619301702150">Visualizzatore certificati</translation>
 <translation id="300526633675317032">Verranno cancellati tutti i <ph name="SIZE_IN_KB" /> di memoria utilizzata dai siti web.</translation>
 <translation id="3008272652534848354">Reimposta le autorizzazioni</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
index 6302fcc..c83d150 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{הוענקו ההרשאות <ph name="PERMISSION_1" />,‏ <ph name="PERMISSION_2" /> ועוד אחת (<ph name="NUM_MORE" />)}two{הוענקו ההרשאות <ph name="PERMISSION_1" />,‏ <ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}many{הוענקו ההרשאות <ph name="PERMISSION_1" />,‏ <ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}other{הוענקו ההרשאות <ph name="PERMISSION_1" />,‏ <ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">ההורדה הושלמה <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">התראות</translation>
+<translation id="2485422356828889247">הסרת התקנה</translation>
 <translation id="2490684707762498678">מנוהלות על-ידי <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">עזרה ומשוב</translation>
 <translation id="2501278716633472235">חזרה</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">כתובות</translation>
 <translation id="2910701580606108292">הצגת שאלה לפני מתן הרשאה לאתרים להפעיל תוכן מוגן</translation>
 <translation id="2913331724188855103">‏אתרים יוכלו לשמור ולקרוא נתונים של קובצי Cookie (מומלץ)</translation>
+<translation id="2932883381142163287">דיווח על שימוש לרעה</translation>
 <translation id="2968755619301702150">מציג האישורים</translation>
 <translation id="300526633675317032">פעולה זו תמחק את כל נתוני האתר המאוחסנים (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">איפוס הרשאות</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
index 469e3df..42cc4e0 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />、<ph name="PERMISSION_2" />、他 <ph name="NUM_MORE" /> 個の権限が許可されています}other{<ph name="PERMISSION_1" />、<ph name="PERMISSION_2" />、他 <ph name="NUM_MORE" /> 個の権限が許可されています}}</translation>
 <translation id="2434158240863470628">ダウンロードが完了しました<ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">通知</translation>
+<translation id="2485422356828889247">アンインストール</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> で管理</translation>
 <translation id="2498359688066513246">ヘルプとフィードバック</translation>
 <translation id="2501278716633472235">戻る</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">住所</translation>
 <translation id="2910701580606108292">保護されたコンテンツの再生をサイトに許可する前に確認する</translation>
 <translation id="2913331724188855103">サイトに Cookie データの保存と読み取りを許可する(推奨)</translation>
+<translation id="2932883381142163287">不正行為を報告</translation>
 <translation id="2968755619301702150">証明書ビューア</translation>
 <translation id="300526633675317032">ウェブサイトのストレージ <ph name="SIZE_IN_KB" /> のデータをすべて削除します。</translation>
 <translation id="3008272652534848354">権限をリセット</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
index 1af3548d..96f951c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> და <ph name="NUM_MORE" /> სხვა დაშვებულია}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> და <ph name="NUM_MORE" /> სხვა დაშვებულია}}</translation>
 <translation id="2434158240863470628">ჩამოტვირთვა დასრულდა: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">შეტყობინებები</translation>
+<translation id="2485422356828889247">დეინსტალაცია</translation>
 <translation id="2490684707762498678">მართავს <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">დახმარება და უკუკავშირი</translation>
 <translation id="2501278716633472235">უკან დაბრუნება</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">მისამართები</translation>
 <translation id="2910701580606108292">შეკითხვა საიტებისთვის დაცული კონტენტის დაკვრის დაშვებამდე</translation>
 <translation id="2913331724188855103">საშუალებას აძლევს საიტებს შეინახონ და გაეცნონ ქუქი ფაილებს (რეკომენდირებული)</translation>
+<translation id="2932883381142163287">არასათანადო მოპყრობის შესახებ შეტყობინება</translation>
 <translation id="2968755619301702150">სერტიფიკატთა მაჩვენებელი</translation>
 <translation id="300526633675317032">ეს მოქმედება მთლიანად გაასუფთავებს ვებსაიტების მეხსიერებას (სულ: <ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">ნებართვების გადაყენება</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
index 791be8d..dd7fac2 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" /> қызметті пайдалануға рұқсат етілген.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" /> қызметті пайдалануға рұқсат етілген.}}</translation>
 <translation id="2434158240863470628"><ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /> жүктеп алынды</translation>
 <translation id="2482878487686419369">Хабарландырулар</translation>
+<translation id="2485422356828889247">Жою</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> басқарады</translation>
 <translation id="2498359688066513246">Анықтама және пікір</translation>
 <translation id="2501278716633472235">Артқа қайту</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Мекенжайлар</translation>
 <translation id="2910701580606108292">Қорғалған мазмұнды ойнатуға рұқсат етпес бұрын сұрау</translation>
 <translation id="2913331724188855103">Сайттарға cookie деректерін сақтауға және оқуға рұқсат беру (ұсынылған)</translation>
+<translation id="2932883381142163287">Бұзақылық туралы хабарлау</translation>
 <translation id="2968755619301702150">Сертификат көру құралы</translation>
 <translation id="300526633675317032">Вебсайттың барлық деректері жойылады (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Рұқсаттарды бастапқы күйіне қайтару</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
index 3c3469d..34483f20 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{បានអនុញ្ញាត <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> និង <ph name="NUM_MORE" /> ទៀត}other{បានអនុញ្ញាត <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> និង <ph name="NUM_MORE" /> ទៀត}}</translation>
 <translation id="2434158240863470628">ការទាញយក​បានបញ្ចប់ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">ការជូនដំណឹង</translation>
+<translation id="2485422356828889247">លុបការតំឡើង</translation>
 <translation id="2490684707762498678">ស្ថិតក្រោម​ការគ្រប់គ្រង​របស់ <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">ជំនួយ &amp; មតិ</translation>
 <translation id="2501278716633472235">ត្រលប់ក្រោយ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">អាសយដ្ឋាន</translation>
 <translation id="2910701580606108292">សួរ​មុនពេល​អនុញ្ញតឱ្យគេហទំព័រ​លេង​ខ្លឹមសារ​ដែលមាន​ការការពារ</translation>
 <translation id="2913331724188855103">អនុញ្ញាតឲ្យគេហទំព័ររក្សាទុក និងអានទិន្នន័យខុកឃី (បានណែនាំ)</translation>
+<translation id="2932883381142163287">របាយការណ៏នៃការបំពាន</translation>
 <translation id="2968755619301702150">កម្មវិធីមើលវិញ្ញាបនប័ត្រ</translation>
 <translation id="300526633675317032">វានឹងជម្រះ <ph name="SIZE_IN_KB" /> ទាំងស្រុងនៃទំហំផ្ទុកគេហទំព័រ</translation>
 <translation id="3008272652534848354">កំណត់​ការអនុញ្ញាត​ឡើងវិញ</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
index 3271fa87..6fcdb06 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತ್ತು ಇನ್ನೂ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತ್ತು ಇನ್ನೂ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತ್ತು ಇನ್ನೂ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ}}</translation>
 <translation id="2434158240863470628">ಡೌನ್‌ಲೋಡ್‌‌ ಪೂರ್ಣಗೊಂಡಿದೆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">ಸೂಚನೆಗಳು</translation>
+<translation id="2485422356828889247">ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ಆ್ಯಪ್ ನಿರ್ವಹಿಸುತ್ತಿದೆ</translation>
 <translation id="2498359688066513246">ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ</translation>
 <translation id="2501278716633472235">ಹಿಂದಿರುಗಿ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ವಿಳಾಸಗಳು</translation>
 <translation id="2910701580606108292">ಸಂರಕ್ಷಿತ ವಿಷಯವನ್ನು ಪ್ಲೇ ಮಾಡಲು ಸೈಟ್‌ಗಳಿಗೆ ಅನುಮತಿಸುವ ಮೊದಲು ಕೇಳಿ</translation>
 <translation id="2913331724188855103">ಕುಕೀ ಡೇಟಾವನ್ನು ಉಳಿಸಲು ಮತ್ತು ರೀಡ್ ಮಾಡಲು ಸೈಟ್‌ಗಳನ್ನು ಅನುಮತಿಸಿ (ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ)</translation>
+<translation id="2932883381142163287">ನಿಂದನೆ ವರದಿ ಮಾಡಿ</translation>
 <translation id="2968755619301702150">ಪ್ರಮಾಣಪತ್ರ ವೀಕ್ಷಕ</translation>
 <translation id="300526633675317032">ಇದು ವೆಬ್‌ಸೈಟ್ ಸಂಗ್ರಹಣೆಯ ಎಲ್ಲಾ <ph name="SIZE_IN_KB" /> ಅನ್ನು ತೆರವುಗೊಳಿಸುತ್ತದೆ.</translation>
 <translation id="3008272652534848354">ಅನುಮತಿಗಳನ್ನು ಮರುಹೊಂದಿಸಿ</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
index 4c2fc31..f189569 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />개 허용됨}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />개 허용됨}}</translation>
 <translation id="2434158240863470628">다운로드 완료: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">알림</translation>
+<translation id="2485422356828889247">제거</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" />에서 관리함</translation>
 <translation id="2498359688066513246">고객센터</translation>
 <translation id="2501278716633472235">뒤로 이동</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">주소</translation>
 <translation id="2910701580606108292">사이트에서 보호된 콘텐츠를 재생하도록 허용하기 전에 확인</translation>
 <translation id="2913331724188855103">사이트에서 쿠키 데이터를 저장하고 읽도록 허용(권장)</translation>
+<translation id="2932883381142163287">악용사례 신고</translation>
 <translation id="2968755619301702150">인증서 뷰어</translation>
 <translation id="300526633675317032">웹사이트 저장공간 <ph name="SIZE_IN_KB" />가 모두 삭제됩니다.</translation>
 <translation id="3008272652534848354">권한 재설정</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
index f1f3d2f..d9c1e2e 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" /> үчүн уруксат берилди}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" /> үчүн уруксат берилди}}</translation>
 <translation id="2434158240863470628">Жүктөлүп алынды: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Билдирмелер</translation>
+<translation id="2485422356828889247">Орнотуудан чыгаруу</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> тарабынан башкарылат</translation>
 <translation id="2498359688066513246">Жардам/пикир билдирүү</translation>
 <translation id="2501278716633472235">Артка кайтуу</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Даректер</translation>
 <translation id="2910701580606108292">Сайттар корголгон мазмунду ойнотуудан мурда уруксат суралсын</translation>
 <translation id="2913331724188855103">Сайттарга куки дайындарын сактоого жана окууга уруксат берүү (сунушталат)</translation>
+<translation id="2932883381142163287">Адепсиздик тууралуу кабарлоо</translation>
 <translation id="2968755619301702150">Тастыктаманы көрүүчү</translation>
 <translation id="300526633675317032">Ушуну менен <ph name="SIZE_IN_KB" /> сайттардын дайындарынын баары тазаланат.</translation>
 <translation id="3008272652534848354">Уруксаттарды өзгөртүү</translation>
@@ -166,7 +168,7 @@
 <translation id="5489227211564503167"><ph name="TOTAL_TIME" /> ичинен <ph name="ELAPSED_TIME" /> өттү.</translation>
 <translation id="5494752089476963479">Тажатма же адаштыруучу жарнамаларды көрсөткөн сайттан келген жарнамалар бөгөттөлсүн</translation>
 <translation id="549957179819296104">Жаңы сүрөтчө</translation>
-<translation id="5502860503640766021"><ph name="PERMISSION_1" /> дайындарына уруксат берилди, <ph name="PERMISSION_2" /> бөгөттөлдү</translation>
+<translation id="5502860503640766021">Уруксат берилген: <ph name="PERMISSION_1" />. Бөгөттөлгөн: <ph name="PERMISSION_2" />.</translation>
 <translation id="5505264765875738116">Сайттар билдирмелерди жөнөтүүнү сурана алышпайт</translation>
 <translation id="5516455585884385570">Билдирменин жөндөөлөрүн ачуу</translation>
 <translation id="5527111080432883924">Алмашуу буфериндеги тексттер жана сүрөттөрдү сайттар окугусу келгенде суралсын (сунушталат)</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
index a7b684c..e26dbcf1 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{ອະນຸຍາດ <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ແລະ ອີກ <ph name="NUM_MORE" /> ລາຍການແລ້ວ}other{ອະນຸຍາດ <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ແລະ ອີກ <ph name="NUM_MORE" /> ລາຍການແລ້ວ}}</translation>
 <translation id="2434158240863470628">ການດາວໂຫຼດສຳເລັດແລ້ວ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">ການແຈ້ງເຕືອນ</translation>
+<translation id="2485422356828889247">ຖອນ​ຕິດ​ຕັ້ງ</translation>
 <translation id="2490684707762498678">ຈັດການໂດຍ <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">ຊ່ວຍເຫຼືອ ​ແລະ ຄໍາ​ຄິດ​ເຫັນຕິ​ຊົມ</translation>
 <translation id="2501278716633472235">ກັບ​ຄືນ​ໄປ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ທີ່​ຢູ່</translation>
 <translation id="2910701580606108292">ຖາມກ່ອນທີ່ຈະອະນຸຍາດໃຫ້ເວັບໄຊຫຼິ້ນເນື້ອຫາທີ່ມີການປ້ອງກັນໄວ້</translation>
 <translation id="2913331724188855103">ອະ​ນຸ​ຍາດ​ໃຫ້​ເວັບ​ໄຊ​ທ໌​ບັນ​ທຶກ ແລະ​ອ່ານ​ຂໍ້​ມູນ​ຄຸກ​ກີ້ (ແນະ​ນຳ​ໃຫ້)</translation>
+<translation id="2932883381142163287">ລາຍງານການນຳ​ໃຊ້​ຜິດ</translation>
 <translation id="2968755619301702150">ຕົວເບິ່ງໃບຢັ້ງຢືນ</translation>
 <translation id="300526633675317032">ນີ້ຈະລຶບລ້າງທັງໝົດ <ph name="SIZE_IN_KB" /> ຂອງບ່ອນເກັບຂໍ້ມູນເວັບໄຊ.</translation>
 <translation id="3008272652534848354">ຣີເຊັດການອະນຸຍາດ</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
index e6dee3e..48730e83 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}one{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}few{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}many{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}other{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Atsisiųsta: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Pranešimai</translation>
+<translation id="2485422356828889247">Pašalinti</translation>
 <translation id="2490684707762498678">Tvarko „<ph name="APP_NAME" />“</translation>
 <translation id="2498359688066513246">Pagalba ir atsiliepimai</translation>
 <translation id="2501278716633472235">Grįžti</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresai</translation>
 <translation id="2910701580606108292">Paklausti prieš leidžiant svetainėms leisti saugomą turinį</translation>
 <translation id="2913331724188855103">Leisti svetainėms išsaugoti ir nuskaityti slapukų duomenis (rekomenduojama)</translation>
+<translation id="2932883381142163287">Pranešti apie piktnaudžiavimą</translation>
 <translation id="2968755619301702150">Sertifikato peržiūros priemonė</translation>
 <translation id="300526633675317032">Bus išvalyta visa <ph name="SIZE_IN_KB" /> svetainės saugykla.</translation>
 <translation id="3008272652534848354">Iš naujo nustatyti leidimus</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
index aa237e7..e2d8a02 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}zero{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}one{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}other{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Lejupielāde pabeigta: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Paziņojumi</translation>
+<translation id="2485422356828889247">Atinstalēt</translation>
 <translation id="2490684707762498678">Pārvalda <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Palīdzība un atsauksmes</translation>
 <translation id="2501278716633472235">Doties atpakaļ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adreses</translation>
 <translation id="2910701580606108292">Jautāt, pirms atļaut vietnēm atskaņot aizsargātu saturu</translation>
 <translation id="2913331724188855103">Atļaut vietnēm saglabāt un lasīt sīkfailu datus (ieteicams)</translation>
+<translation id="2932883381142163287">Ziņot par ļaunprātīgu izmantošanu</translation>
 <translation id="2968755619301702150">Sertifikātu skatītājs</translation>
 <translation id="300526633675317032">Tādējādi tiks notīrīti visi vietnes krātuves dati (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Atiestatīt atļaujas</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
index 3d08f54..f84787d2 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> се одобрени}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> се одобрени}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> се одобрени}}</translation>
 <translation id="2434158240863470628">Преземањето е завршено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Известувања</translation>
+<translation id="2485422356828889247">Деинсталирај</translation>
 <translation id="2490684707762498678">Управувани од <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Помош и повратни информации</translation>
 <translation id="2501278716633472235">Врати се</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Адреси</translation>
 <translation id="2910701580606108292">Прашај пред да дозволиш сајтовите да пуштаат заштитени содржини</translation>
 <translation id="2913331724188855103">Дозволете локациите да зачувуваат и читаат податоци за колачињата (препорачано)</translation>
+<translation id="2932883381142163287">Пријави злоупотреба</translation>
 <translation id="2968755619301702150">Прикажувач на сертификат</translation>
 <translation id="300526633675317032">Ова ќе ги избрише сите <ph name="SIZE_IN_KB" /> од просторот на веб-сајтот.</translation>
 <translation id="3008272652534848354">Ресетирај ги дозволите</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
index 48d02c9..01f878f 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> എന്നിവയും മറ്റ് <ph name="NUM_MORE" /> എണ്ണവും അനുവദിച്ചു}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> എന്നിവയും മറ്റ് <ph name="NUM_MORE" /> എണ്ണവും അനുവദിച്ചു}}</translation>
 <translation id="2434158240863470628">ഡൗൺലോഡ് പൂർത്തിയായി <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">അറിയിപ്പുകൾ</translation>
+<translation id="2485422356828889247">അണ്‍‌ഇന്‍‌സ്റ്റാള്‍‌ ചെയ്യുക</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ആണ് മാനേജ് ചെയ്യുന്നത്</translation>
 <translation id="2498359688066513246">സഹായവും ഫീഡ്ബാക്കും</translation>
 <translation id="2501278716633472235">പിന്നോട്ട് പോകുക</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">വിലാസങ്ങള്‍‌</translation>
 <translation id="2910701580606108292">പരിരക്ഷിത ഉള്ളടക്കം പ്ലേ ചെയ്യാൻ സൈറ്റുകളെ അനുവദിക്കുന്നതിന് മുമ്പ് ചോദിക്കുക</translation>
 <translation id="2913331724188855103">കുക്കി ഡാറ്റ സംരക്ഷിക്കുന്നതിനും വായിക്കുന്നതിനും സൈറ്റുകളെ അനുവദിക്കുക (ശുപാർശചെയ്‌തത്)</translation>
+<translation id="2932883381142163287">ദുരുപയോഗം റിപ്പോര്‍ട്ട് ചെയ്യുക</translation>
 <translation id="2968755619301702150">സർട്ടിഫിക്കറ്റ് വ്യൂവർ</translation>
 <translation id="300526633675317032">ഇത് വെബ്‌സൈറ്റ് സ്‌റ്റോറേജിലെ <ph name="SIZE_IN_KB" /> പൂർണ്ണമായും മായ്‌ക്കും.</translation>
 <translation id="3008272652534848354">അനുമതികൾ പുനഃസജ്ജീകരിക്കുക</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
index bba6216..645f423a 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон бусад <ph name="NUM_MORE" />-г зөвшөөрсөн}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон бусад <ph name="NUM_MORE" />-г зөвшөөрсөн}}</translation>
 <translation id="2434158240863470628">Татаж дууссан <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Мэдэгдэл</translation>
+<translation id="2485422356828889247">Устгах</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" />-с удирддаг</translation>
 <translation id="2498359688066513246">Тусламж болон санал хүсэлт</translation>
 <translation id="2501278716633472235">Буцаах</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Хаягууд</translation>
 <translation id="2910701580606108292">Сайтад хамгаалалттай контент тоглуулахыг зөвшөөрөхөөс өмнө асуух</translation>
 <translation id="2913331724188855103">Cookie data-г хадгалах мөн унших боломжийг сайтуудад олгох (зөвлөж байна)</translation>
+<translation id="2932883381142163287">Зөрчлийг мэдэгдэх</translation>
 <translation id="2968755619301702150">Сертификат харагч</translation>
 <translation id="300526633675317032">Энэ нь веб хуудасны сангийн бүх <ph name="SIZE_IN_KB" />-г устгах болно.</translation>
 <translation id="3008272652534848354">Зөвшөөрлийг шинэчлэх</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
index f872e0d..c13e2a6 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" /> ला अनुमती दिली}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" /> ना अनुमती दिली}}</translation>
 <translation id="2434158240863470628">डाउनलोड पूर्ण झाले <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">सूचना</translation>
+<translation id="2485422356828889247">अनइंस्टॉल करा</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> द्वारे व्यवस्थापित केले आहे</translation>
 <translation id="2498359688066513246">मदत आणि अभिप्राय</translation>
 <translation id="2501278716633472235">परत जा</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">पत्ते</translation>
 <translation id="2910701580606108292">सायटींना संरक्षित आशय प्ले करू देण्याआधी विचारा</translation>
 <translation id="2913331724188855103">कुकी डेटा सेव्ह करणे आणि वाचण्यासाठी साइटना अनुमती द्या (शिफारस केलेले)</translation>
+<translation id="2932883381142163287">दुरुपयोगाची तक्रार नोंदवा</translation>
 <translation id="2968755619301702150">सर्टिफिकेट दर्शक</translation>
 <translation id="300526633675317032">हे सर्व <ph name="SIZE_IN_KB" /> वेबसाइट स्टोरेज साफ करेल.</translation>
 <translation id="3008272652534848354">परवानग्या रीसेट करा</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
index 10d9967..028c19c6 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi dibenarkan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi dibenarkan}}</translation>
 <translation id="2434158240863470628">Muat turun selesai: <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Pemberitahuan</translation>
+<translation id="2485422356828889247">Nyahpasang</translation>
 <translation id="2490684707762498678">Diurus oleh <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Bantuan &amp; maklum balas</translation>
 <translation id="2501278716633472235">Kembali</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Alamat</translation>
 <translation id="2910701580606108292">Tanya sebelum membenarkan tapak memainkan kandungan yang dilindungi</translation>
 <translation id="2913331724188855103">Benarkan tapak untuk menyimpan dan membaca data kuki (disyorkan)</translation>
+<translation id="2932883381142163287">Laporkan penyalahgunaan</translation>
 <translation id="2968755619301702150">Pemapar sijil</translation>
 <translation id="300526633675317032">Tindakan ini akan menghapuskan semua <ph name="SIZE_IN_KB" /> daripada storan tapak web.</translation>
 <translation id="3008272652534848354">Tetapkan semula kebenaran</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
index 4505815..b809fd2 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />၊ <ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> ခု ခွင့်ပြုထားသည်}other{<ph name="PERMISSION_1" />၊ <ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> ခု ခွင့်ပြုထားသည်}}</translation>
 <translation id="2434158240863470628">ဒေါင်းလုဒ်လုပ်ပြီးပါပြီ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">အကြောင်းကြားစာ</translation>
+<translation id="2485422356828889247">ဖြုတ်ရန်</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> က စီမံခန့်ခွဲထားပါသည်</translation>
 <translation id="2498359688066513246">အကူအညီ &amp; အကြံပြုချက်</translation>
 <translation id="2501278716633472235">နောက်သို့ ပြန်ရန်</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">လိပ်စာများ</translation>
 <translation id="2910701580606108292">ဝဘ်ဆိုက်များအား ကာကွယ်ထားသည့် အကြောင်းအရာများကို ပြသခွင့် မပြုမီ ဦးစွာ မေးပါ</translation>
 <translation id="2913331724188855103">ဆိုဒ်များကို ကွက်ကီးများ ဖတ်ရန်နှင့် သိမ်းရန် ခွင့်ပြုသည် (အကြံပြုထား)</translation>
+<translation id="2932883381142163287">အလွဲသုံးစားပြုခြင်းအား အစီရင်ခံရန်</translation>
 <translation id="2968755619301702150">လက်မှတ်ကို ကြည့်ရှုသူ</translation>
 <translation id="300526633675317032">၎င်းသည် ဝဘ်ဆိုက်သိုလှောင်ခန်း၏ <ph name="SIZE_IN_KB" /> ကို ရှင်းလင်းလိုက်ပါမည်။</translation>
 <translation id="3008272652534848354">ခွင့်ပြုချက်များကို ပြင်ဆင်သတ်မှတ်ရန်</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
index 9456649..469d915 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
@@ -57,6 +57,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" /> सुविधासम्बन्धी अनुमति दिइएको छ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" /> सुविधासम्बन्धी अनुमति दिइएको छ}}</translation>
 <translation id="2434158240863470628">डाउनलोड सम्पन्न भयो <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">सूचनाहरू</translation>
+<translation id="2485422356828889247">विस्थापन गर्नुहोस्</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ले व्यवस्थापन गरेको</translation>
 <translation id="2498359688066513246">मद्दत र प्रतिक्रिया</translation>
 <translation id="2501278716633472235">पछाडि जानुहोस्</translation>
@@ -76,6 +77,7 @@
 <translation id="2903493209154104877">ठेगानाहरू</translation>
 <translation id="2910701580606108292">साइटहरूलाई संरक्षित सामग्री प्ले गर्ने अनुमति दिनुअघि सोध्नुहोस्</translation>
 <translation id="2913331724188855103">साइटहरूलाई कुकी डेटा सुरक्षित गर्ने र पढ्ने अनुमति दिनुहोस् (सिफारिस गरिएको)</translation>
+<translation id="2932883381142163287">दुरूपयोग रिपोर्ट गर्नुहोस्</translation>
 <translation id="2968755619301702150">प्रमाणपत्र दर्शक</translation>
 <translation id="300526633675317032">यसले वेबसाइटको भण्डारणको सबै <ph name="SIZE_IN_KB" /> खाली गर्ने छ।</translation>
 <translation id="3008272652534848354">अनुमतिहरू रिसेट गर्नुहोस्</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
index fc52ef67..176c746 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> toegestaan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> toegestaan}}</translation>
 <translation id="2434158240863470628">Download voltooid <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Meldingen</translation>
+<translation id="2485422356828889247">Installatie ongedaan maken</translation>
 <translation id="2490684707762498678">Beheerd door <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Hulp en feedback</translation>
 <translation id="2501278716633472235">Terug</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adressen</translation>
 <translation id="2910701580606108292">Vragen voordat sites beschermde content mogen afspelen</translation>
 <translation id="2913331724188855103">Sites toestaan cookiegegevens op te slaan en te lezen (aanbevolen)</translation>
+<translation id="2932883381142163287">Misbruik melden</translation>
 <translation id="2968755619301702150">Certificaatviewer</translation>
 <translation id="300526633675317032">Hiermee wordt de volledige <ph name="SIZE_IN_KB" /> aan site-opslag gewist.</translation>
 <translation id="3008272652534848354">Rechten resetten</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
index a49b99f2..1e543f3 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til er tillatt}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til er tillatt}}</translation>
 <translation id="2434158240863470628">Nedlasting fullført <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Varsler</translation>
+<translation id="2485422356828889247">Avinstaller</translation>
 <translation id="2490684707762498678">Administreres av <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Hjelp og tilbakemelding</translation>
 <translation id="2501278716633472235">Gå tilbake</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresser</translation>
 <translation id="2910701580606108292">Spør før nettsteder kan spille av beskyttet innhold</translation>
 <translation id="2913331724188855103">Tillat at nettsteder lagrer og leser data i informasjonskapsler (anbefales)</translation>
+<translation id="2932883381142163287">Rapportér misbruk</translation>
 <translation id="2968755619301702150">Visningsprogram for sertifikater</translation>
 <translation id="300526633675317032">Dette sletter alle dataene (<ph name="SIZE_IN_KB" />) fra nettstedslagringen.</translation>
 <translation id="3008272652534848354">Tilbakestill tillatelser</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
index f517765..3d3cd66 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ଏବଂ ଅଧିକ <ph name="NUM_MORE" />ଟିକୁ ଅନୁମତି ଦିଆଯାଇଛି}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ଏବଂ ଅଧିକ <ph name="NUM_MORE" />ଟିକୁ ଅନୁମତି ଦିଆଯାଇଛି}}</translation>
 <translation id="2434158240863470628">ଡାଉନ୍‌ଲୋଡ୍ ଶେଷ ହେଲା <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">ବିଜ୍ଞପ୍ତି</translation>
+<translation id="2485422356828889247">ଅନ୍‍ଇନ୍‍ଷ୍ଟଲ୍‌ କରନ୍ତୁ</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ଦ୍ୱାରା ପରିଚାଳିତ</translation>
 <translation id="2498359688066513246">ସାହାଯ୍ୟ ଓ ମତାମତ</translation>
 <translation id="2501278716633472235">ଫେରନ୍ତୁ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ଠିକଣାଗୁଡ଼ିକ</translation>
 <translation id="2910701580606108292">ସାଇଟ୍‌ଗୁଡ଼ିକୁ ସୁରକ୍ଷିତ ବିଷୟବସ୍ତୁ ଚଲାଇବା ପାଇଁ ଅନୁମତି ଦେବା ପୂର୍ବରୁ, ପଚାରନ୍ତୁ</translation>
 <translation id="2913331724188855103">କୁକୀ ଡାଟାଗୁଡ଼ିକୁ ସେଭ୍ କରିବାକୁ ଏବଂ ପଢ଼ିବା ପାଇଁ ସାଇଟ୍‌ଗୁଡ଼ିକୁ ଅନୁମତି ଦିଅନ୍ତୁ (ସୁପାରିଶ୍ କରାଯାଇଛି)</translation>
+<translation id="2932883381142163287">ନିର୍ଯ୍ୟାତନାର ରିପୋର୍ଟ କରନ୍ତୁ</translation>
 <translation id="2968755619301702150">ସାର୍ଟିଫିକେଟ୍‌ ଭ୍ୟୁଅର୍‌</translation>
 <translation id="300526633675317032">ଏହା ୱେବ୍‌ସାଇଟ୍‌ ଷ୍ଟୋରେଜ୍‌ର ସମସ୍ତ <ph name="SIZE_IN_KB" /> ଡାଟା ଖାଲି କରିବ।</translation>
 <translation id="3008272652534848354">ଅନୁମତି ରିସେଟ୍ କରନ୍ତୁ</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
index 3c3cf3d3..8861c1c4 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}}</translation>
 <translation id="2434158240863470628">ਡਾਊਨਲੋਡ ਮੁਕੰਮਲ ਹੋਇਆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">ਸੂਚਨਾਵਾਂ</translation>
+<translation id="2485422356828889247">ਅਣਸਥਾਪਤ ਕਰੋ</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ਵੱਲੋਂ ਪ੍ਰਬੰਧਨ ਕੀਤਾ ਜਾਂਦਾ ਹੈ</translation>
 <translation id="2498359688066513246">ਮਦਦ ਅਤੇ ਪ੍ਰਤੀਕਰਮ</translation>
 <translation id="2501278716633472235">ਪਿੱਛੇ ਜਾਓ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ਪਤੇ</translation>
 <translation id="2910701580606108292">ਸਾਈਟਾਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਸਮੱਗਰੀ ਚਲਾਉਣ ਦੇਣ ਤੋਂ ਪਹਿਲਾਂ ਪੁੱਛੋ</translation>
 <translation id="2913331724188855103">ਸਾਈਟਾਂ ਨੂੰ ਕੁਕੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕਰਨ ਅਤੇ ਪੜ੍ਹਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
+<translation id="2932883381142163287">ਦੁਰਵਿਵਹਾਰ ਦੀ ਰਿਪੋਰਟ ਕਰੋ</translation>
 <translation id="2968755619301702150">ਪ੍ਰਮਾਣ-ਪੱਤਰ ਵਿਊਅਰ</translation>
 <translation id="300526633675317032">ਇਸ ਨਾਲ ਵੈੱਬਸਾਈਟ ਸਟੋਰੇਜ ਦਾ ਸਾਰਾ <ph name="SIZE_IN_KB" /> ਡਾਟਾ ਕਲੀਅਰ ਹੋ ਜਾਵੇਗਾ।</translation>
 <translation id="3008272652534848354">ਇਜਾਜ਼ਤਾਂ ਰੀਸੈੱਟ ਕਰੋ</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
index b9d8d6127..4b246e06 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}few{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}many{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}other{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Ukończono pobieranie <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Powiadomienia</translation>
+<translation id="2485422356828889247">Odinstaluj</translation>
 <translation id="2490684707762498678">Zarządzane przez <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Pomoc i opinie</translation>
 <translation id="2501278716633472235">Wróć</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresy</translation>
 <translation id="2910701580606108292">Pytaj, zanim zezwolisz stronom na odtwarzanie treści chronionej</translation>
 <translation id="2913331724188855103">Zezwalaj witrynom na zapisywanie danych w plikach cookie i ich odczytywanie (zalecane)</translation>
+<translation id="2932883381142163287">Zgłoś nadużycie</translation>
 <translation id="2968755619301702150">Przeglądarka certyfikatów</translation>
 <translation id="300526633675317032">Spowoduje to usunięcie <ph name="SIZE_IN_KB" /> danych witryn.</translation>
 <translation id="3008272652534848354">Zresetuj uprawnienia</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
index c4253f6..76920783 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}one{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}other{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Download concluído <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificações</translation>
+<translation id="2485422356828889247">Desinstalar</translation>
 <translation id="2490684707762498678">Gerenciadas por <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ajuda e feedback</translation>
 <translation id="2501278716633472235">Voltar</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Endereços</translation>
 <translation id="2910701580606108292">Perguntar antes de permitir que sites mostrem conteúdo protegido</translation>
 <translation id="2913331724188855103">Permitir que os sites salvem e leiam os dados de arquivos "cookies" - que armazenam temporariamente o que você visitou na rede. (Recomendado)</translation>
+<translation id="2932883381142163287">Denunciar abuso</translation>
 <translation id="2968755619301702150">Leitor de certificados</translation>
 <translation id="300526633675317032">Essa ação apagará tudo, <ph name="SIZE_IN_KB" /> de dados de armazenamento de sites.</translation>
 <translation id="3008272652534848354">Redefinir permissões</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
index 7bd38d02..199f98c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}}</translation>
 <translation id="2434158240863470628">Transferência concluída: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificações</translation>
+<translation id="2485422356828889247">Desinstalar</translation>
 <translation id="2490684707762498678">Gerido por <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ajuda e comentários</translation>
 <translation id="2501278716633472235">Voltar</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Endereços</translation>
 <translation id="2910701580606108292">Perguntar antes de permitir que os sites reproduzam conteúdos protegidos</translation>
 <translation id="2913331724188855103">Permitir que os sites guardem e leiam dados de cookies (recomendado)</translation>
+<translation id="2932883381142163287">Denunciar abuso</translation>
 <translation id="2968755619301702150">Visualizador de certificados</translation>
 <translation id="300526633675317032">Esta ação elimina os <ph name="SIZE_IN_KB" /> de armazenamento do Website.</translation>
 <translation id="3008272652534848354">Repor autorizações</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
index 37f9b5e..1a7cdc9 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}}</translation>
 <translation id="2434158240863470628">Descărcare finalizată <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Notificări</translation>
+<translation id="2485422356828889247">Dezinstalează</translation>
 <translation id="2490684707762498678">Gestionate de <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ajutor și feedback</translation>
 <translation id="2501278716633472235">Înapoi</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adrese</translation>
 <translation id="2910701580606108292">Întreabă înainte de a permite site-urilor să redea conținut protejat</translation>
 <translation id="2913331724188855103">Permite site-urilor să salveze și să citească datele asociate cookie-urilor (recomandat)</translation>
+<translation id="2932883381142163287">Raportează un abuz</translation>
 <translation id="2968755619301702150">Vizualizator de certificate</translation>
 <translation id="300526633675317032">Astfel, se vor șterge <ph name="SIZE_IN_KB" /> din stocarea site-urilor.</translation>
 <translation id="3008272652534848354">Resetează permisiunile</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
index 2b837c3b..6197d06 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}one{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}few{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}many{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}other{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Скачивание завершено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Уведомления</translation>
+<translation id="2485422356828889247">Удалить</translation>
 <translation id="2490684707762498678">Под управлением приложения "<ph name="APP_NAME" />"</translation>
 <translation id="2498359688066513246">Справка/отзыв</translation>
 <translation id="2501278716633472235">Назад</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Адреса</translation>
 <translation id="2910701580606108292">Запрашивать разрешение на воспроизведение защищенного контента</translation>
 <translation id="2913331724188855103">Разрешить сайтам сохранять и читать файлы cookie (рекомендуется)</translation>
+<translation id="2932883381142163287">Сообщить о нарушении</translation>
 <translation id="2968755619301702150">Просмотр сертификатов</translation>
 <translation id="300526633675317032">Будут удалены все данные сайтов (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Сбросить все разрешения</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
index 83e0623..8f2804df 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}}</translation>
 <translation id="2434158240863470628">බාගැනීම සම්පූර්ණයි <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">දැනුම්දීම්</translation>
+<translation id="2485422356828889247">අස්ථාපනය</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> විසින් කළමනා කෙරේ</translation>
 <translation id="2498359688066513246">උදවු සහ ප්‍රතිපෝෂණය</translation>
 <translation id="2501278716633472235">ආපසු යන්න</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ලිපින</translation>
 <translation id="2910701580606108292">ආරක්ෂිත අන්තර්ගත වාදනය කිරීමට ඉඩ දීමට පෙර විමසන්න (නිර්දේශිතයි)</translation>
 <translation id="2913331724188855103">අඩවි වලට කුකී දත්ත සුරැකීමට සහ කුකී දත්ත කියවන්න (නිර්දේශිතයි)</translation>
+<translation id="2932883381142163287">අපහරණය වාර්තා කරන්න</translation>
 <translation id="2968755619301702150">සහතික දක්වනය</translation>
 <translation id="300526633675317032">මෙය වෙබ් අඩවි ආචයනයේ සියලු <ph name="SIZE_IN_KB" /> හිස් කරනු ඇත.</translation>
 <translation id="3008272652534848354">අවසර යළි සකසන්න</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
index 5f0ff20..63fa73c9 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ďalšie}few{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ďalšie}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ďalších}}</translation>
 <translation id="2434158240863470628">Sťahovanie bolo dokončené <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Upozornenia</translation>
+<translation id="2485422356828889247">Odinštalovať</translation>
 <translation id="2490684707762498678">Spravuje <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Pomocník a spätná väzba</translation>
 <translation id="2501278716633472235">Prejsť späť</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresy</translation>
 <translation id="2910701580606108292">Pýtať sa, či chcete povoliť webu prehrávať chránený obsah</translation>
 <translation id="2913331724188855103">Povoliť webom ukladať a čítať súbory cookie (odporučané)</translation>
+<translation id="2932883381142163287">Nahlásiť zneužitie</translation>
 <translation id="2968755619301702150">Zobrazovač certifikátov</translation>
 <translation id="300526633675317032">Vymažete celé úložisko webu (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Obnoviť povolenia</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
index ae51407..043d69c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in še <ph name="NUM_MORE" />}one{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in še <ph name="NUM_MORE" />}two{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in še <ph name="NUM_MORE" />}few{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in še <ph name="NUM_MORE" />}other{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in še <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Prenos je končan <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Obvestila</translation>
+<translation id="2485422356828889247">Odmeščanje</translation>
 <translation id="2490684707762498678">Upravlja aplikacija <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Pomoč in povratne inform.</translation>
 <translation id="2501278716633472235">Nazaj</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Naslovi</translation>
 <translation id="2910701580606108292">Prikaži poziv, preden se spletnim mestom dovoli predvajanje zaščitene vsebine</translation>
 <translation id="2913331724188855103">Spletnim mestom dovoli shranjevanje in branje podatkov piškotkov (priporočljivo)</translation>
+<translation id="2932883381142163287">Prijavite zlorabo</translation>
 <translation id="2968755619301702150">Pregledovalnik potrdil</translation>
 <translation id="300526633675317032">S tem bo izbrisanih vseh <ph name="SIZE_IN_KB" /> shranjenih podatkov spletnega mesta.</translation>
 <translation id="3008272652534848354">Ponastavi dovoljenja</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
index 87ab7fc..70f6710 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> tjetër e lejuar}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> të tjera të lejuara}}</translation>
 <translation id="2434158240863470628">Shkarkimi përfundoi <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Njoftimet</translation>
+<translation id="2485422356828889247">Çinstalo</translation>
 <translation id="2490684707762498678">Menaxhuar nga <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Ndihmë dhe komente</translation>
 <translation id="2501278716633472235">Kthehu prapa</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresat</translation>
 <translation id="2910701580606108292">Pyet përpara se sajtet të lejohen të luajnë përmbajtje të mbrojtura</translation>
 <translation id="2913331724188855103">Lejo faqet të ruajnë dhe lexojnë të dhënat e kukive (rekomandohet)</translation>
+<translation id="2932883381142163287">Raporto abuzim</translation>
 <translation id="2968755619301702150">Shikuesi i certifikatave</translation>
 <translation id="300526633675317032">Kjo do të pastrojë të gjitha <ph name="SIZE_IN_KB" /> të hapësirës ruajtëse të sajtit të uebit.</translation>
 <translation id="3008272652534848354">Rivendos autorizimet</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
index e20d3171..7f4a3b0 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Preuzimanje je završeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Obaveštenja</translation>
+<translation id="2485422356828889247">Deinstaliraj</translation>
 <translation id="2490684707762498678">Upravlja <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Pomoć i povratne informacije</translation>
 <translation id="2501278716633472235">Nazad</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adrese</translation>
 <translation id="2910701580606108292">Pitaj pre nego što dozvoliš sajtovima da puštaju zaštićeni sadržaj</translation>
 <translation id="2913331724188855103">Dozvoli sajtovima da čuvaju i čitaju podatke kolačića (preporučuje se)</translation>
+<translation id="2932883381142163287">Prijavi zloupotrebu</translation>
 <translation id="2968755619301702150">Prikazivač sertifikata</translation>
 <translation id="300526633675317032">Ovim ćete obrisati ceo memorijski prostor veb-sajta od <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Resetuj dozvole</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
index 1e3146b..bfa8544 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Одобрене су дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}one{Одобрене су дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}few{Одобрене су дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}other{Одобрене су дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Преузимање је завршено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Обавештења</translation>
+<translation id="2485422356828889247">Деинсталирај</translation>
 <translation id="2490684707762498678">Управља <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Помоћ и повратне информације</translation>
 <translation id="2501278716633472235">Назад</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Адресе</translation>
 <translation id="2910701580606108292">Питај пре него што дозволиш сајтовима да пуштају заштићени садржај</translation>
 <translation id="2913331724188855103">Дозволи сајтовима да чувају и читају податке колачића (препоручује се)</translation>
+<translation id="2932883381142163287">Пријави злоупотребу</translation>
 <translation id="2968755619301702150">Приказивач сертификата</translation>
 <translation id="300526633675317032">Овим ћете обрисати цео меморијски простор веб-сајта од <ph name="SIZE_IN_KB" />.</translation>
 <translation id="3008272652534848354">Ресетуј дозволе</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
index 20b4855..0d42a25 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till tillåts}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till tillåts}}</translation>
 <translation id="2434158240863470628">Nedladdningen är klar<ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Aviseringar</translation>
+<translation id="2485422356828889247">Avinstallera</translation>
 <translation id="2490684707762498678">Hanteras av <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Hjälp och feedback</translation>
 <translation id="2501278716633472235">Föregående</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresser</translation>
 <translation id="2910701580606108292">Fråga innan webbplatser tillåts att spela upp skyddat innehåll</translation>
 <translation id="2913331724188855103">Tillåt att webbplatser sparar och läser cookiedata (rekommenderas)</translation>
+<translation id="2932883381142163287">Anmäl otillåten användning</translation>
 <translation id="2968755619301702150">Certifikatvisare</translation>
 <translation id="300526633675317032">Det här alternativet tar bort alla <ph name="SIZE_IN_KB" /> webbplatslagring.</translation>
 <translation id="3008272652534848354">Återställ behörigheter</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
index 0bab788..f71a7ce 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Umeruhusu <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine<ph name="NUM_MORE" />}other{Umeruhusu <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine<ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Upakuaji umekamilika <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Arifa</translation>
+<translation id="2485422356828889247">Ondoa</translation>
 <translation id="2490684707762498678">Inasimamiwa na <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Usaidizi na maoni</translation>
 <translation id="2501278716633472235">Rudi nyuma</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Anwani</translation>
 <translation id="2910701580606108292">Iulize kabla ya kuruhusu tovuti kucheza maudhui yanayolindwa</translation>
 <translation id="2913331724188855103">Ruhusu tovuti zihifadhi na kusoma data ya vidakuzi (imependekezwa)</translation>
+<translation id="2932883381142163287">Ripoti matumizi mabaya</translation>
 <translation id="2968755619301702150">Kitazamaji vyeti</translation>
 <translation id="300526633675317032">Hatua hii itafuta <ph name="SIZE_IN_KB" /> yote ya hifadhi ya tovuti.</translation>
 <translation id="3008272652534848354">Badilisha ruhusa</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
index 9ecdde2..60abb59 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலும் <ph name="NUM_MORE" /> அனுமதிகள் வழங்கப்பட்டுள்ளன}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலும் <ph name="NUM_MORE" /> அனுமதிகள் வழங்கப்பட்டுள்ளன}}</translation>
 <translation id="2434158240863470628">பதிவிறக்கம் முடிந்தது <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">அறிவிப்புகள்</translation>
+<translation id="2485422356828889247">நிறுவல் நீக்கு</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> நிர்வகிக்கிறது</translation>
 <translation id="2498359688066513246">உதவி &amp; கருத்து</translation>
 <translation id="2501278716633472235">திரும்பிச் செல்</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">முகவரிகள்</translation>
 <translation id="2910701580606108292">பாதுகாக்கப்பட்ட உள்ளடக்கத்தை இயக்குவதற்குத் தளங்களை அனுமதிக்கும் முன்பு அனுமதி கோரும்</translation>
 <translation id="2913331724188855103">குக்கீத் தரவை, தளங்கள் சேமிக்கவும் படிக்கவும் அனுமதி (பரிந்துரைக்கப்பட்டது)</translation>
+<translation id="2932883381142163287">முறைகேடெனப் புகாரளி</translation>
 <translation id="2968755619301702150">சான்றிதழ் வியூவர்</translation>
 <translation id="300526633675317032">இணையதளச் சேமிப்பகத்தில் உள்ள <ph name="SIZE_IN_KB" /> தரவையும் இது அழிக்கும்.</translation>
 <translation id="3008272652534848354">அனுமதிகளை மீட்டமை</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
index 6660b24..7f110c5 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> అనుమతించబడ్డాయి}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> అనుమతించబడ్డాయి}}</translation>
 <translation id="2434158240863470628">డౌన్‌లోడ్ పూర్తయింది <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">నోటిఫికేషన్‌లు</translation>
+<translation id="2485422356828889247">అన్ఇన్‌స్టాల్ చేయి</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> ద్వారా నిర్వహించబడుతున్నాయి</translation>
 <translation id="2498359688066513246">సహాయం &amp; అభిప్రాయం</translation>
 <translation id="2501278716633472235">వెనుకకు వెళ్ళు</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">అడ్రస్‌లు</translation>
 <translation id="2910701580606108292">సైట్‌లు రక్షిత కంటెంట్‌ను ప్లే చేయడానికి ముందు అనుమతి కోసం అడుగుతాయి</translation>
 <translation id="2913331724188855103">కుక్కీ డేటాను సేవ్ చేయడానికి, చదవడానికి సైట్‌లను అనుమతిస్తుంది (సిఫార్సు చేయబడింది)</translation>
+<translation id="2932883381142163287">దుర్వినియోగాన్ని రిపోర్ట్ చేయి</translation>
 <translation id="2968755619301702150">ప్రమాణపత్రం వ్యూయర్</translation>
 <translation id="300526633675317032">ఇది వెబ్‌సైట్ నిల్వలోని మొత్తం <ph name="SIZE_IN_KB" />ను తీసివేస్తుంది.</translation>
 <translation id="3008272652534848354">అనుమతులను రీసెట్ చేయి</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
index 1bc750c..4718df1 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{อนุญาตให้เข้าถึง<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> และอีก <ph name="NUM_MORE" /> รายการ}other{อนุญาตให้เข้าถึง<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> และอีก <ph name="NUM_MORE" /> รายการ}}</translation>
 <translation id="2434158240863470628">ดาวน์โหลดเสร็จสมบูรณ์ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">การแจ้งเตือน</translation>
+<translation id="2485422356828889247">ถอนการติดตั้ง</translation>
 <translation id="2490684707762498678">จัดการโดย <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">ความช่วยเหลือและความคิดเห็น</translation>
 <translation id="2501278716633472235">ย้อนกลับ</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">ที่อยู่</translation>
 <translation id="2910701580606108292">ถามก่อนอนุญาตให้เว็บไซต์เล่นเนื้อหาที่ได้รับความคุ้มครอง</translation>
 <translation id="2913331724188855103">อนุญาตให้เว็บไซต์บันทึกและอ่านข้อมูลคุกกี้ (แนะนำ)</translation>
+<translation id="2932883381142163287">รายงานการละเมิด</translation>
 <translation id="2968755619301702150">เครื่องมือดูใบรับรอง</translation>
 <translation id="300526633675317032">การดำเนินการนี้จะล้างพื้นที่เก็บข้อมูลเว็บไซต์ทั้ง <ph name="SIZE_IN_KB" /></translation>
 <translation id="3008272652534848354">รีเซ็ตสิทธิ์</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
index 5be00cf..22df43a 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tanesi için daha izin verildi}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tanesi için daha izin verildi}}</translation>
 <translation id="2434158240863470628">İndirme işlemi tamamlandı <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Bildirimler</translation>
+<translation id="2485422356828889247">Kaldır</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> tarafından yönetiliyor</translation>
 <translation id="2498359688066513246">Yardım ve geri bildirim</translation>
 <translation id="2501278716633472235">Geri dön</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Adresler</translation>
 <translation id="2910701580606108292">Sitelerin korumalı içeriği oynatmasına izin verilmeden önce size sorulur</translation>
 <translation id="2913331724188855103">Sitelerin, çerez verilerini kaydetmelerine ve okumalarına izin ver (önerilir)</translation>
+<translation id="2932883381142163287">Kötüye kullanım bildir</translation>
 <translation id="2968755619301702150">Sertifika görüntüleyici</translation>
 <translation id="300526633675317032">Bu işlem <ph name="SIZE_IN_KB" /> olan web sitesi depolama alanının tamamını temizleyecek.</translation>
 <translation id="3008272652534848354">İzinleri sıfırla</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
index 653f06e..c7e247c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}one{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}few{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}many{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}other{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}}</translation>
 <translation id="2434158240863470628">Завантажено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Сповіщення</translation>
+<translation id="2485422356828889247">Видалити</translation>
 <translation id="2490684707762498678">Адміністратор сімейної групи: <ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Довідка й відгуки</translation>
 <translation id="2501278716633472235">Назад</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Адреси</translation>
 <translation id="2910701580606108292">Запитувати, перш ніж дозволяти сайтам відтворювати захищений вміст</translation>
 <translation id="2913331724188855103">Дозволити сайтам зберігати та розпізнавати дані файлів cookie (рекомендується)</translation>
+<translation id="2932883381142163287">Повідомити про порушення</translation>
 <translation id="2968755619301702150">Перегляд сертифікатів</translation>
 <translation id="300526633675317032">Буде видалено всі дані сайтів (<ph name="SIZE_IN_KB" />).</translation>
 <translation id="3008272652534848354">Скинути дозволи</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
index f5703db..a18446c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید کی اجازت دی گئی}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید کی اجازت دی گئی}}</translation>
 <translation id="2434158240863470628">ڈاؤن لوڈ مکمل ہو گیا <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">اطلاعات</translation>
+<translation id="2485422356828889247">ان انسٹال کریں</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> کے زیر انتظام</translation>
 <translation id="2498359688066513246">مدد اور تاثرات</translation>
 <translation id="2501278716633472235">پیچھے جائیں</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">پتے</translation>
 <translation id="2910701580606108292">سائٹس کو محفوظ مواد چلانے کی اجازت دینے سے پہلے پوچھیں</translation>
 <translation id="2913331724188855103">سائٹس کو کوکی ڈیٹا کو محفوظ کرنے اور پڑھنے کی اجازت دیں (تجویز کردہ)</translation>
+<translation id="2932883381142163287">بیجا استعمال کی اطلاع دیں</translation>
 <translation id="2968755619301702150">سرٹیفیکیٹ ناظر</translation>
 <translation id="300526633675317032">اس سے ویب سائٹ اسٹوریج کا کُل <ph name="SIZE_IN_KB" /> صاف ہو جائے گا۔</translation>
 <translation id="3008272652534848354">اجازتیں دوبارہ ترتیب دیں</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
index 68422701..0d50e6e 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Ruxsat berildi: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}other{Ruxsat berildi: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}}</translation>
 <translation id="2434158240863470628">Yuklab olindi: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Bildirishnomalar</translation>
+<translation id="2485422356828889247">O‘chirib tashlash</translation>
 <translation id="2490684707762498678"><ph name="APP_NAME" /> tomonidan boshqariladi</translation>
 <translation id="2498359688066513246">Yordam/fikr-mulohaza</translation>
 <translation id="2501278716633472235">Ortga qaytish</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Manzillar</translation>
 <translation id="2910701580606108292">Himoyalangan kontentni ijro etishdan avval ruxsat so‘ralsin</translation>
 <translation id="2913331724188855103">Saytlarga cookie-fayllarini saqlash va o’qishga ruxsat berish (tavsiya etiladi)</translation>
+<translation id="2932883381142163287">Shikoyat xabari yuborish</translation>
 <translation id="2968755619301702150">Sertifikatlarni ko‘rish vositasi</translation>
 <translation id="300526633675317032">Veb-sayt xotirasidan <ph name="SIZE_IN_KB" /> tozalanadi.</translation>
 <translation id="3008272652534848354">Ruxsatlarni qasliga qaytarish</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
index e492ca6..4675fc36 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Đã cho phép <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyền khác}other{Đã cho phép <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyền khác}}</translation>
 <translation id="2434158240863470628">Quá trình tải xuống hoàn tất <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Thông báo</translation>
+<translation id="2485422356828889247">Gỡ cài đặt</translation>
 <translation id="2490684707762498678">Do <ph name="APP_NAME" /> quản lý</translation>
 <translation id="2498359688066513246">Trợ giúp và phản hồi</translation>
 <translation id="2501278716633472235">Quay lại</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Địa chỉ</translation>
 <translation id="2910701580606108292">Hỏi trước khi cho phép trang web phát nội dung được bảo vệ</translation>
 <translation id="2913331724188855103">Cho phép các trang web lưu và đọc dữ liệu cookie (nên chọn)</translation>
+<translation id="2932883381142163287">Báo cáo lạm dụng</translation>
 <translation id="2968755619301702150">Trình xem chứng chỉ</translation>
 <translation id="300526633675317032">Thao tác này sẽ xóa tất cả <ph name="SIZE_IN_KB" /> bộ nhớ trang web.</translation>
 <translation id="3008272652534848354">Đặt lại quyền</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
index af2b7f99..b6beb49 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{已授予“<ph name="PERMISSION_1" />”权限、“<ph name="PERMISSION_2" />”权限和另外 <ph name="NUM_MORE" /> 项权限}other{已授予“<ph name="PERMISSION_1" />”权限、“<ph name="PERMISSION_2" />”权限和另外 <ph name="NUM_MORE" /> 项权限}}</translation>
 <translation id="2434158240863470628">下载完成 <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">通知</translation>
+<translation id="2485422356828889247">卸载</translation>
 <translation id="2490684707762498678">由 <ph name="APP_NAME" /> 管理</translation>
 <translation id="2498359688066513246">帮助和反馈</translation>
 <translation id="2501278716633472235">返回</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">地址</translation>
 <translation id="2910701580606108292">需先询问,得到许可后才允许网站播放受保护的内容</translation>
 <translation id="2913331724188855103">允许网站保存和读取 Cookie 数据(推荐)</translation>
+<translation id="2932883381142163287">举报滥用行为</translation>
 <translation id="2968755619301702150">证书查看器</translation>
 <translation id="300526633675317032">这会清除全部的网站存储数据 (<ph name="SIZE_IN_KB" />)。</translation>
 <translation id="3008272652534848354">重置权限</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
index 40441014..a13e9d4 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{已允許「<ph name="PERMISSION_1" />」、「<ph name="PERMISSION_2" />」和另外 <ph name="NUM_MORE" /> 項權限}other{已允許「<ph name="PERMISSION_1" />」、「<ph name="PERMISSION_2" />」和另外 <ph name="NUM_MORE" /> 項權限}}</translation>
 <translation id="2434158240863470628">下載完成 <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">通知</translation>
+<translation id="2485422356828889247">解除安裝</translation>
 <translation id="2490684707762498678">由 <ph name="APP_NAME" /> 管理</translation>
 <translation id="2498359688066513246">說明和意見反映</translation>
 <translation id="2501278716633472235">返回</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">地址</translation>
 <translation id="2910701580606108292">網站播放受保護內容前先詢問您</translation>
 <translation id="2913331724188855103">允許網站儲存及讀取 Cookie 資料 (建議)</translation>
+<translation id="2932883381142163287">舉報濫用</translation>
 <translation id="2968755619301702150">憑證檢視者</translation>
 <translation id="300526633675317032">這會將網站儲存空間的 <ph name="SIZE_IN_KB" /> 資料全部清除。</translation>
 <translation id="3008272652534848354">重設權限</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
index d1aa0296..ed0c37c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{已允許「<ph name="PERMISSION_1" />」、「<ph name="PERMISSION_2" />」和另外 <ph name="NUM_MORE" /> 項權限}other{已允許「<ph name="PERMISSION_1" />」、「<ph name="PERMISSION_2" />」和另外 <ph name="NUM_MORE" /> 項權限}}</translation>
 <translation id="2434158240863470628">下載完成 <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">通知</translation>
+<translation id="2485422356828889247">解除安裝</translation>
 <translation id="2490684707762498678">由 <ph name="APP_NAME" /> 管理</translation>
 <translation id="2498359688066513246">說明與意見回饋</translation>
 <translation id="2501278716633472235">返回</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">地址</translation>
 <translation id="2910701580606108292">允許網站播放受保護的內容前,必須先詢問你</translation>
 <translation id="2913331724188855103">允許網站儲存及讀取 Cookie 資料 (建議)</translation>
+<translation id="2932883381142163287">檢舉濫用情形</translation>
 <translation id="2968755619301702150">憑證檢視器</translation>
 <translation id="300526633675317032">這會將網站儲存的資料全部清除 (共 <ph name="SIZE_IN_KB" />)。</translation>
 <translation id="3008272652534848354">重設權限</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
index 8bbec39..5458402 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
@@ -58,6 +58,7 @@
 <translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}one{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}other{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}}</translation>
 <translation id="2434158240863470628">Ukulanda kuqedile <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
 <translation id="2482878487686419369">Izaziso</translation>
+<translation id="2485422356828889247">Khipha</translation>
 <translation id="2490684707762498678">Ilawulwa ngu-<ph name="APP_NAME" /></translation>
 <translation id="2498359688066513246">Usizo nempendulo</translation>
 <translation id="2501278716633472235">Iya emuva</translation>
@@ -77,6 +78,7 @@
 <translation id="2903493209154104877">Amakheli</translation>
 <translation id="2910701580606108292">Buza ngaphambi kokuvumela amasayithi ukudlala okuqukethwe okuvikelwe</translation>
 <translation id="2913331724188855103">Vumela amasayithi ukulondoloza nokufunda idatha yamakhukhi (kunconyiwe)</translation>
+<translation id="2932883381142163287">Bika ukuhlukumeza</translation>
 <translation id="2968755619301702150">Isibukeli sesitifiketi</translation>
 <translation id="300526633675317032">Lokhu kuzosula yonke i-<ph name="SIZE_IN_KB" /> yesitoreji sewebhusayithi.</translation>
 <translation id="3008272652534848354">Setha kabusha izimvume</translation>
diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc
index df9136ae..6144f35 100644
--- a/components/content_settings/core/browser/content_settings_pref.cc
+++ b/components/content_settings/core/browser/content_settings_pref.cc
@@ -27,6 +27,7 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "services/preferences/public/cpp/dictionary_value_update.h"
 #include "services/preferences/public/cpp/scoped_pref_update.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 
 namespace {
@@ -81,8 +82,7 @@
 // SessionModel::Durable if no model exists.
 content_settings::SessionModel GetSessionModel(
     const base::DictionaryValue* dictionary) {
-  int model_int = 0;
-  dictionary->GetIntegerWithoutPathExpansion(kSessionModelPath, &model_int);
+  int model_int = dictionary->FindIntKey(kSessionModelPath).value_or(0);
   if ((model_int >
        static_cast<int>(content_settings::SessionModel::kMaxValue)) ||
       (model_int < 0)) {
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index a511ea49..b538ddc0 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -414,12 +414,12 @@
 
 void ClientControlledShellSurface::SetSnappedToLeft() {
   TRACE_EVENT0("exo", "ClientControlledShellSurface::SetSnappedToLeft");
-  pending_window_state_ = chromeos::WindowStateType::kLeftSnapped;
+  pending_window_state_ = chromeos::WindowStateType::kPrimarySnapped;
 }
 
 void ClientControlledShellSurface::SetSnappedToRight() {
   TRACE_EVENT0("exo", "ClientControlledShellSurface::SetSnappedToRight");
-  pending_window_state_ = chromeos::WindowStateType::kRightSnapped;
+  pending_window_state_ = chromeos::WindowStateType::kSecondarySnapped;
 }
 
 void ClientControlledShellSurface::SetPip() {
@@ -1447,8 +1447,8 @@
   // the window bounds instead for maximixed state.
   // Snapped window states in tablet mode do not include the caption height.
   const bool is_snapped =
-      window_state == chromeos::WindowStateType::kLeftSnapped ||
-      window_state == chromeos::WindowStateType::kRightSnapped;
+      window_state == chromeos::WindowStateType::kPrimarySnapped ||
+      window_state == chromeos::WindowStateType::kSecondarySnapped;
   const bool is_maximized =
       window_state == chromeos::WindowStateType::kMaximized;
   const display::TabletState tablet_state =
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index 8542f1a..71e4fdd 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1080,7 +1080,7 @@
   window1->SetBounds(split_view_controller->GetSnappedWindowBoundsInScreen(
       ash::SplitViewController::LEFT, window1));
   state1->set_bounds_locally(false);
-  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
+  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kPrimarySnapped);
   EXPECT_EQ(shell_surface1->GetWidget()->GetWindowBoundsInScreen(),
             split_view_controller->GetSnappedWindowBoundsInScreen(
                 ash::SplitViewController::LEFT,
@@ -1094,7 +1094,7 @@
   window1->SetBounds(split_view_controller->GetSnappedWindowBoundsInScreen(
       ash::SplitViewController::RIGHT, window1));
   state1->set_bounds_locally(false);
-  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kRightSnapped);
+  EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kSecondarySnapped);
   EXPECT_EQ(shell_surface1->GetWidget()->GetWindowBoundsInScreen(),
             split_view_controller->GetSnappedWindowBoundsInScreen(
                 ash::SplitViewController::RIGHT,
@@ -1297,7 +1297,7 @@
   shell->overview_controller()->EndOverview();
   SendGestureEvents(window, gfx::Point(0, 210));
   EXPECT_EQ(ash::WindowState::Get(window)->GetStateType(),
-            WindowStateType::kLeftSnapped);
+            WindowStateType::kPrimarySnapped);
 }
 
 namespace {
@@ -2061,9 +2061,9 @@
 
   EnableTabletMode(true);
 
-  ash::WMEvent event(ash::WM_EVENT_SNAP_LEFT);
+  ash::WMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&event);
-  EXPECT_EQ(window_state->GetStateType(), WindowStateType::kLeftSnapped);
+  EXPECT_EQ(window_state->GetStateType(), WindowStateType::kPrimarySnapped);
 
   ash::NonClientFrameViewAsh* frame_view =
       static_cast<ash::NonClientFrameViewAsh*>(
@@ -2152,8 +2152,8 @@
   surface->SetFrame(SurfaceFrameType::NORMAL);
   surface->Commit();
   shell_surface->OnBoundsChangeEvent(WindowStateType::kMinimized,
-                                     WindowStateType::kRightSnapped, display_id,
-                                     gfx::Rect(0, 0, 100, 100), 0);
+                                     WindowStateType::kSecondarySnapped,
+                                     display_id, gfx::Rect(0, 0, 100, 100), 0);
   EXPECT_EQ(3, delegate->bounds_change_count());
   EXPECT_EQ(
       frame_view->GetClientBoundsForWindowBounds(gfx::Rect(0, 0, 100, 100)),
@@ -2163,8 +2163,8 @@
   // Snapped, in tablet mode.
   EnableTabletMode(true);
   shell_surface->OnBoundsChangeEvent(WindowStateType::kMinimized,
-                                     WindowStateType::kRightSnapped, display_id,
-                                     gfx::Rect(0, 0, 100, 100), 0);
+                                     WindowStateType::kSecondarySnapped,
+                                     display_id, gfx::Rect(0, 0, 100, 100), 0);
   EXPECT_EQ(4, delegate->bounds_change_count());
   EXPECT_EQ(gfx::Rect(0, 0, 100, 100), delegate->requested_bounds().back());
 }
@@ -2686,7 +2686,7 @@
   surface->Commit();
   EXPECT_EQ(gfx::Rect(50, 68, 200, 332), widget->GetWindowBoundsInScreen());
 
-  ash::WMEvent event(ash::WM_EVENT_SNAP_LEFT);
+  ash::WMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
   ash::WindowState::Get(window)->OnWMEvent(&event);
   EXPECT_EQ(gfx::Rect(0, 32, 400, 568), delegate->requested_bounds().back());
 
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 718ebe63..1318ad0 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -902,7 +902,7 @@
   EXPECT_EQ(buffer_size,
             shell_surface->GetWidget()->GetWindowBoundsInScreen().size());
 
-  ash::WMEvent event(ash::WM_EVENT_CYCLE_SNAP_LEFT);
+  ash::WMEvent event(ash::WM_EVENT_CYCLE_SNAP_PRIMARY);
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
 
   // Enter snapped mode.
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc
index d9a8506..46e0cbff 100644
--- a/components/exo/test/exo_test_helper.cc
+++ b/components/exo/test/exo_test_helper.cc
@@ -94,10 +94,10 @@
   shell_surface_->SetBounds(display_id, bounds_in_display);
 
   if (requested_state != window_state->GetStateType()) {
-    DCHECK(requested_state == chromeos::WindowStateType::kLeftSnapped ||
-           requested_state == chromeos::WindowStateType::kRightSnapped);
+    DCHECK(requested_state == chromeos::WindowStateType::kPrimarySnapped ||
+           requested_state == chromeos::WindowStateType::kSecondarySnapped);
 
-    if (requested_state == chromeos::WindowStateType::kLeftSnapped)
+    if (requested_state == chromeos::WindowStateType::kPrimarySnapped)
       shell_surface_->SetSnappedToLeft();
     else
       shell_surface_->SetSnappedToRight();
diff --git a/components/exo/wayland/zcr_remote_shell.cc b/components/exo/wayland/zcr_remote_shell.cc
index f0457d7..7961f3b 100644
--- a/components/exo/wayland/zcr_remote_shell.cc
+++ b/components/exo/wayland/zcr_remote_shell.cc
@@ -1304,9 +1304,9 @@
     // Override the reason only if the window enters snapped mode. If the window
     // resizes by dragging in snapped mode, we need to keep the original reason.
     if (requested_state != current_state) {
-      if (requested_state == WindowStateType::kLeftSnapped) {
+      if (requested_state == WindowStateType::kPrimarySnapped) {
         reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT;
-      } else if (requested_state == WindowStateType::kRightSnapped) {
+      } else if (requested_state == WindowStateType::kSecondarySnapped) {
         reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT;
       }
     }
@@ -1383,10 +1383,10 @@
       case WindowStateType::kTrustedPinned:
         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED;
         break;
-      case WindowStateType::kLeftSnapped:
+      case WindowStateType::kPrimarySnapped:
         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_LEFT_SNAPPED;
         break;
-      case WindowStateType::kRightSnapped:
+      case WindowStateType::kSecondarySnapped:
         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED;
         break;
       case WindowStateType::kPip:
diff --git a/components/nacl/renderer/json_manifest.cc b/components/nacl/renderer/json_manifest.cc
index 6ff0064..3cfbd117 100644
--- a/components/nacl/renderer/json_manifest.cc
+++ b/components/nacl/renderer/json_manifest.cc
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "components/nacl/common/nacl_types.h"
 #include "components/nacl/renderer/nexe_load_manager.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 
 namespace nacl {
@@ -381,12 +382,10 @@
   DCHECK(get_url_success);
   pnacl_options->translate = PP_TRUE;
   if (url_spec.HasKey(kOptLevelKey)) {
-    int32_t opt_raw = 0;
-    bool get_opt_success =
-        url_spec.GetIntegerWithoutPathExpansion(kOptLevelKey, &opt_raw);
-    DCHECK(get_opt_success);
+    absl::optional<int32_t> opt_raw = url_spec.FindIntKey(kOptLevelKey);
+    DCHECK(opt_raw.has_value());
     // Currently only allow 0 or 2, since that is what we test.
-    if (opt_raw <= 0)
+    if (opt_raw.value() <= 0)
       pnacl_options->opt_level = 0;
     else
       pnacl_options->opt_level = 2;
diff --git a/components/optimization_guide/core/optimization_guide_util.cc b/components/optimization_guide/core/optimization_guide_util.cc
index bcd2f73..183f676 100644
--- a/components/optimization_guide/core/optimization_guide_util.cc
+++ b/components/optimization_guide/core/optimization_guide_util.cc
@@ -26,6 +26,12 @@
       return "LanguageDetection";
     case proto::OPTIMIZATION_TARGET_PAGE_TOPICS:
       return "PageTopics";
+    case proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB:
+      return "SegmentationNewTab";
+    case proto::OPTIMIZATION_TARGET_SEGMENTATION_SHARE:
+      return "SegmentationShare";
+    case proto::OPTIMIZATION_TARGET_SEGMENTATION_VOICE:
+      return "SegmentationVoice";
   }
   NOTREACHED();
   return std::string();
diff --git a/components/optimization_guide/proto/models.proto b/components/optimization_guide/proto/models.proto
index a9a89e1..74b95ac4 100644
--- a/components/optimization_guide/proto/models.proto
+++ b/components/optimization_guide/proto/models.proto
@@ -230,6 +230,12 @@
   OPTIMIZATION_TARGET_LANGUAGE_DETECTION = 2;
   // Target for determining topics present on a page.
   OPTIMIZATION_TARGET_PAGE_TOPICS = 3;
+  // Target for segmentation: New tab page user.
+  OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB = 4;
+  // Target for segmentation: Share user.
+  OPTIMIZATION_TARGET_SEGMENTATION_SHARE = 5;
+  // Target for segmentation: Voice user.
+  OPTIMIZATION_TARGET_SEGMENTATION_VOICE = 6;
 }
 
 // The types of models that can be evaluated.
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
index f86d8b7..496dd903 100644
--- a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -227,8 +227,7 @@
     const ApplicationLocaleGetter& application_locale_getter,
     base::TickClock* clock,
     heavy_ad_intervention::HeavyAdBlocklist* blocklist)
-    : subresource_observer_(this),
-      clock_(clock ? clock : base::DefaultTickClock::GetInstance()),
+    : clock_(clock ? clock : base::DefaultTickClock::GetInstance()),
       restricted_navigation_ad_tagging_enabled_(base::FeatureList::IsEnabled(
           features::kRestrictedNavigationAdTagging)),
       heavy_ad_service_(heavy_ad_service),
@@ -257,7 +256,7 @@
   // |observer_manager| isn't constructed if the feature for subresource
   // filtering isn't enabled.
   if (observer_manager)
-    subresource_observer_.Add(observer_manager);
+    subresource_observation_.Observe(observer_manager);
   aggregate_frame_data_ = std::make_unique<AggregateFrameData>();
   return CONTINUE_OBSERVING;
 }
@@ -697,7 +696,7 @@
 }
 
 void AdsPageLoadMetricsObserver::OnSubresourceFilterGoingAway() {
-  subresource_observer_.RemoveAll();
+  subresource_observation_.Reset();
 }
 
 void AdsPageLoadMetricsObserver::OnPageActivationComputed(
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h
index 6401cd8..84566d39 100644
--- a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/field_trial_params.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/time/tick_clock.h"
 #include "build/build_config.h"
 #include "components/blocklist/opt_out_blocklist/opt_out_blocklist_data.h"
@@ -276,9 +276,9 @@
   // the frame elements are being destroyed in the renderer.
   bool process_display_state_updates_ = true;
 
-  ScopedObserver<subresource_filter::SubresourceFilterObserverManager,
-                 subresource_filter::SubresourceFilterObserver>
-      subresource_observer_;
+  base::ScopedObservation<subresource_filter::SubresourceFilterObserverManager,
+                          subresource_filter::SubresourceFilterObserver>
+      subresource_observation_{this};
 
   // The tick clock used to get the current time. Can be replaced by tests.
   const base::TickClock* clock_;
diff --git a/components/password_manager/core/browser/browser_save_password_progress_logger.cc b/components/password_manager/core/browser/browser_save_password_progress_logger.cc
index 6aa946c..36e69d58 100644
--- a/components/password_manager/core/browser/browser_save_password_progress_logger.cc
+++ b/components/password_manager/core/browser/browser_save_password_progress_logger.cc
@@ -333,6 +333,22 @@
   LogValue(label, log);
 }
 
+void BrowserSavePasswordProgressLogger::LogPasswordRequirements(
+    const GURL& origin,
+    autofill::FormSignature form_signature,
+    autofill::FieldSignature field_signature,
+    const autofill::PasswordRequirementsSpec& spec) {
+  std::ostringstream s;
+  s << "Joint password requirements: {\n"
+    << GetStringFromID(STRING_ORIGIN) << ": " << ScrubURL(origin) << "\n"
+    << GetStringFromID(STRING_FORM_SIGNATURE) << ": "
+    << FormSignatureToDebugString(form_signature) << "\n"
+    << "Field signature: " << NumberToString(field_signature.value()) << "\n"
+    << "Requirements:" << spec << "\n"
+    << "}";
+  SendLog(s.str());
+}
+
 void BrowserSavePasswordProgressLogger::SendLog(const std::string& log) {
   log_manager_->LogTextMessage(log);
 }
diff --git a/components/password_manager/core/browser/browser_save_password_progress_logger.h b/components/password_manager/core/browser/browser_save_password_progress_logger.h
index 6cfbac4b..47621c19 100644
--- a/components/password_manager/core/browser/browser_save_password_progress_logger.h
+++ b/components/password_manager/core/browser/browser_save_password_progress_logger.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "components/autofill/core/browser/proto/password_requirements.pb.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom.h"
 #include "components/autofill/core/common/save_password_progress_logger.h"
 #include "url/gurl.h"
@@ -50,6 +51,12 @@
 
   void LogPasswordForm(StringID label, const PasswordForm& form);
 
+  // Log password requirements.
+  void LogPasswordRequirements(const GURL& origin,
+                               autofill::FormSignature form_signature,
+                               autofill::FieldSignature field_signature,
+                               const autofill::PasswordRequirementsSpec& spec);
+
  protected:
   // autofill::SavePasswordProgressLogger:
   void SendLog(const std::string& log) override;
diff --git a/components/password_manager/core/browser/password_generation_frame_helper.cc b/components/password_manager/core/browser/password_generation_frame_helper.cc
index 6845605..cc2ef9b 100644
--- a/components/password_manager/core/browser/password_generation_frame_helper.cc
+++ b/components/password_manager/core/browser/password_generation_frame_helper.cc
@@ -134,6 +134,12 @@
   if (spec.has_max_length() && spec.max_length() < target_length)
     target_length = spec.max_length();
   spec.set_max_length(target_length);
+  if (password_manager_util::IsLoggingActive(client_)) {
+    BrowserSavePasswordProgressLogger logger(client_->GetLogManager());
+    logger.LogPasswordRequirements(last_committed_url.GetOrigin(),
+                                   form_signature, field_signature, spec);
+  }
+
   return autofill::GeneratePassword(spec);
 }
 
diff --git a/components/password_manager/core/browser/password_generation_manager.cc b/components/password_manager/core/browser/password_generation_manager.cc
index ed55a845..a765776 100644
--- a/components/password_manager/core/browser/password_generation_manager.cc
+++ b/components/password_manager/core/browser/password_generation_manager.cc
@@ -279,7 +279,9 @@
     bool accepted,
     const PasswordForm& pending) {
   weak_factory_.InvalidateWeakPtrs();
-  if (accepted) {
+  if (driver && accepted) {
+    // See https://crbug.com/1210341 for when `driver` might be null due to a
+    // compromised renderer.
     driver->GeneratedPasswordAccepted(pending.password_value);
   }
 }
diff --git a/components/policy/core/common/BUILD.gn b/components/policy/core/common/BUILD.gn
index d926df20..e736df923 100644
--- a/components/policy/core/common/BUILD.gn
+++ b/components/policy/core/common/BUILD.gn
@@ -32,6 +32,8 @@
     "cloud/chrome_browser_cloud_management_metrics.h",
     "cloud/cloud_external_data_manager.cc",
     "cloud/cloud_external_data_manager.h",
+    "cloud/cloud_external_data_store.cc",
+    "cloud/cloud_external_data_store.h",
     "cloud/cloud_policy_client.cc",
     "cloud/cloud_policy_client.h",
     "cloud/cloud_policy_client_registration_helper.cc",
@@ -237,6 +239,8 @@
   if (is_android || is_ios) {
     sources += [ "cloud/component_cloud_policy_service_stub.cc" ]
     sources -= [
+      "cloud/cloud_external_data_store.cc",
+      "cloud/cloud_external_data_store.h",
       "cloud/component_cloud_policy_service.cc",
       "cloud/component_cloud_policy_store.cc",
       "cloud/component_cloud_policy_store.h",
@@ -490,6 +494,7 @@
   }
   if (!is_android && !is_ios) {
     sources += [
+      "cloud/cloud_external_data_store_unittest.cc",
       "cloud/component_cloud_policy_service_unittest.cc",
       "cloud/component_cloud_policy_store_unittest.cc",
       "cloud/component_cloud_policy_updater_unittest.cc",
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_store.cc b/components/policy/core/common/cloud/cloud_external_data_store.cc
similarity index 94%
rename from chrome/browser/chromeos/policy/cloud_external_data_store.cc
rename to components/policy/core/common/cloud/cloud_external_data_store.cc
index 1a763be..d50334be 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_store.cc
+++ b/components/policy/core/common/cloud/cloud_external_data_store.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/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 
 #include <set>
 
@@ -30,10 +30,7 @@
     const std::string& cache_key,
     scoped_refptr<base::SequencedTaskRunner> task_runner,
     ResourceCache* cache)
-    : cache_key_(cache_key),
-      task_runner_(task_runner),
-      cache_(cache) {
-}
+    : cache_key_(cache_key), task_runner_(task_runner), cache_(cache) {}
 
 CloudExternalDataStore::~CloudExternalDataStore() {
   // No RunsTasksInCurrentSequence() check to avoid unit tests failures.
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_store.h b/components/policy/core/common/cloud/cloud_external_data_store.h
similarity index 88%
rename from chrome/browser/chromeos/policy/cloud_external_data_store.h
rename to components/policy/core/common/cloud/cloud_external_data_store.h
index 644ee72..22583a24 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_store.h
+++ b/components/policy/core/common/cloud/cloud_external_data_store.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 CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_STORE_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_STORE_H_
+#ifndef COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_EXTERNAL_DATA_STORE_H_
+#define COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_EXTERNAL_DATA_STORE_H_
 
 #include <stddef.h>
 
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
+#include "components/policy/policy_export.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -32,7 +33,7 @@
 // * Stores sharing a cache must use different cache_keys to avoid namespace
 //   overlaps.
 // * The cache must outlive all stores using it.
-class CloudExternalDataStore {
+class POLICY_EXPORT CloudExternalDataStore {
  public:
   CloudExternalDataStore(const std::string& cache_key,
                          scoped_refptr<base::SequencedTaskRunner> task_runner,
@@ -72,4 +73,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_STORE_H_
+#endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_EXTERNAL_DATA_STORE_H_
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc b/components/policy/core/common/cloud/cloud_external_data_store_unittest.cc
similarity index 91%
rename from chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc
rename to components/policy/core/common/cloud/cloud_external_data_store_unittest.cc
index 4f026a3..ee45e84 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_external_data_store_unittest.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/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_external_data_store.h"
 
 #include <stddef.h>
 
@@ -32,9 +32,9 @@
 
 }  // namespace
 
-class CouldExternalDataStoreTest : public testing::Test {
+class CloudExternalDataStoreTest : public testing::Test {
  public:
-  CouldExternalDataStoreTest();
+  CloudExternalDataStoreTest();
 
   void SetUp() override;
 
@@ -47,23 +47,22 @@
   std::unique_ptr<ResourceCache> resource_cache_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(CouldExternalDataStoreTest);
+  DISALLOW_COPY_AND_ASSIGN(CloudExternalDataStoreTest);
 };
 
-CouldExternalDataStoreTest::CouldExternalDataStoreTest()
+CloudExternalDataStoreTest::CloudExternalDataStoreTest()
     : kData1Hash(crypto::SHA256HashString(kData1)),
       kData2Hash(crypto::SHA256HashString(kData2)),
-      task_runner_(new base::TestSimpleTaskRunner) {
-}
+      task_runner_(new base::TestSimpleTaskRunner) {}
 
-void CouldExternalDataStoreTest::SetUp() {
+void CloudExternalDataStoreTest::SetUp() {
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   resource_cache_ =
       std::make_unique<ResourceCache>(temp_dir_.GetPath(), task_runner_,
                                       /* max_cache_size */ absl::nullopt);
 }
 
-TEST_F(CouldExternalDataStoreTest, StoreAndLoad) {
+TEST_F(CloudExternalDataStoreTest, StoreAndLoad) {
   // Write an entry to a store.
   CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
   EXPECT_FALSE(store.Store(kPolicy1, kData1Hash, kData1).empty());
@@ -77,7 +76,7 @@
   EXPECT_EQ(kData1, data);
 }
 
-TEST_F(CouldExternalDataStoreTest, StoreTooLargeAndLoad) {
+TEST_F(CloudExternalDataStoreTest, StoreTooLargeAndLoad) {
   // Write an entry to a store.
   CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
   EXPECT_FALSE(store.Store(kPolicy1, kData1Hash, kData2).empty());
@@ -100,7 +99,7 @@
   EXPECT_TRUE(contents.empty());
 }
 
-TEST_F(CouldExternalDataStoreTest, StoreInvalidAndLoad) {
+TEST_F(CloudExternalDataStoreTest, StoreInvalidAndLoad) {
   // Construct a store entry whose hash and contents do not match.
   CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
   EXPECT_FALSE(store.Store(kPolicy1, kData1Hash, kData2).empty());
@@ -122,7 +121,7 @@
   EXPECT_TRUE(contents.empty());
 }
 
-TEST_F(CouldExternalDataStoreTest, Prune) {
+TEST_F(CloudExternalDataStoreTest, Prune) {
   // Write two entries to a store.
   CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
   EXPECT_FALSE(store.Store(kPolicy1, kData1Hash, kData1).empty());
@@ -161,7 +160,7 @@
   EXPECT_TRUE(contents.empty());
 }
 
-TEST_F(CouldExternalDataStoreTest, SharedCache) {
+TEST_F(CloudExternalDataStoreTest, SharedCache) {
   // Write entries to two stores for two different cache_keys sharing a cache.
   CloudExternalDataStore store1(kKey1, task_runner_, resource_cache_.get());
   EXPECT_FALSE(store1.Store(kPolicy1, kData1Hash, kData1).empty());
diff --git a/components/policy/resources/policy_templates_de.xtb b/components/policy/resources/policy_templates_de.xtb
index d1378be7..4dffa0d 100644
--- a/components/policy/resources/policy_templates_de.xtb
+++ b/components/policy/resources/policy_templates_de.xtb
@@ -3647,9 +3647,6 @@
       Wenn die Richtlinie deaktiviert oder nicht konfiguriert ist, ist der intelligente Akkulademodus immer deaktiviert.
 
       Nutzer können diese Einstellung nicht ändern.</translation>
-<translation id="5845686745936515940">Hiermit kann für alle Cookies das alte "<ph name="ATTRIBUTE_SAMESITE_NAME" />"-Verhalten wiederhergestellt werden. Wird es wiederhergestellt, werden Cookies, für die kein "<ph name="ATTRIBUTE_SAMESITE_NAME" />"-Attribut angegeben ist, so behandelt, als würden sie "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" enthalten. Außerdem wird nicht mehr vorausgesetzt, dass Cookies mit dem Attribut "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" auch das Attribut "<ph name="ATTRIBUTE_SECURE_NAME" />" enthalten müssen, und bei der Auswertung, ob zwei Websites identisch sind, werden die Schemata nicht verglichen. Eine vollständige Beschreibung steht unter https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies zur Verfügung.
-
-          Wenn diese Richtlinie nicht konfiguriert ist, hängt das Standardverhalten von "<ph name="ATTRIBUTE_SAMESITE_NAME" />" für Cookies von der jeweiligen Konfiguration der "<ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />"-, "<ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" />"- und "<ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />"-Funktion ab. Dies kann im Rahmen einer Testphase oder durch Aktivieren oder Deaktivieren des "<ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />"-, "<ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" />"- oder "<ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />"-Status festgelegt werden.</translation>
 <translation id="5848438019586925019">Algorithmus für die Generierung von Schlüsselpaaren.</translation>
 <translation id="585270638818921943">Nutzer daran hindern, Android-Apps aus nicht vertrauenswürdigen Quellen zu verwenden</translation>
 <translation id="5859344336338527083">Wenn diese Richtlinie konfiguriert ist, wird festgelegt, über welche URLs Erweiterungen, Apps und Designs installiert werden dürfen. Vor <ph name="PRODUCT_NAME" />-Version 21 konnten Nutzer auf den Link zu einer CRX-Datei klicken und die Datei nach einigen Hinweisen in <ph name="PRODUCT_NAME" /> installieren. In allen nachfolgenden Versionen müssen solche Dateien zuerst heruntergeladen und dann auf die Seite "Einstellungen" in <ph name="PRODUCT_NAME" /> gezogen werden. Anhand dieser Einstellung kann bei bestimmten URLs der alte, einfachere Installationsvorgang angewendet werden.
diff --git a/components/policy/resources/policy_templates_es-419.xtb b/components/policy/resources/policy_templates_es-419.xtb
index e9cc612..3be9cae9 100644
--- a/components/policy/resources/policy_templates_es-419.xtb
+++ b/components/policy/resources/policy_templates_es-419.xtb
@@ -3671,9 +3671,6 @@
       Si se inhabilita la política o no se establece, se mantendrá desactivado el modo avanzado de carga de la batería.
 
       Los usuarios no podrán cambiar esta configuración.</translation>
-<translation id="5845686745936515940">Permite revertir el comportamiento de todas las cookies conforme al atributo heredado <ph name="ATTRIBUTE_SAMESITE_NAME" />. Si se revierte el comportamiento conforme al atributo heredado, las cookies que no tengan un atributo <ph name="ATTRIBUTE_SAMESITE_NAME" /> especificado se tratarán según el atributo "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />", las cookies con el atributo "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" ya no necesitarán el atributo "<ph name="ATTRIBUTE_SECURE_NAME" />", y se omitirá la comparación de esquemas cuando se evalúa si dos sitios son el mismo sitio. Para obtener la descripción completa, consulta https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Si no se establece esta política, el comportamiento predeterminado <ph name="ATTRIBUTE_SAMESITE_NAME" /> para las cookies dependerá de la configuración personal del usuario para las funciones <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> y <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />, las cuales pueden establecerse con una prueba pública o si se habilitan o inhabilitan las marcas <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> o <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />, respectivamente.</translation>
 <translation id="5848438019586925019">El algoritmo para la generación del par de claves.</translation>
 <translation id="585270638818921943">Impide que el usuario use apps para Android de fuentes no confiables</translation>
 <translation id="5859344336338527083">Si estableces esta política, se especificarán las URL que pueden instalar extensiones, apps y temas. Antes de la versión <ph name="PRODUCT_NAME" /> 21, los usuarios podían hacer clic en un vínculo que los dirigía a un archivo *.crx y <ph name="PRODUCT_NAME" /> ofrecía instalar el archivo después de unas advertencias. A partir de esa versión, este tipo de archivos debe descargarse y arrastrarse a la página de configuración de <ph name="PRODUCT_NAME" />. Esta configuración permite especificar las URL que tendrán el flujo de instalación anterior, que es más sencillo.
diff --git a/components/policy/resources/policy_templates_es.xtb b/components/policy/resources/policy_templates_es.xtb
index f01405efb..5bfd777 100644
--- a/components/policy/resources/policy_templates_es.xtb
+++ b/components/policy/resources/policy_templates_es.xtb
@@ -3688,9 +3688,6 @@
       Si se inhabilita esta política o no se le asigna ningún valor, el modo avanzado de carga de la batería quedará desactivado.
 
       Los usuarios no podrán modificar este ajuste.</translation>
-<translation id="5845686745936515940">Permite restablecer la configuración de comportamiento de cookies antigua de <ph name="ATTRIBUTE_SAMESITE_NAME" />. Si restableces la configuración de comportamiento antigua, las cookies que no especifiquen ningún atributo <ph name="ATTRIBUTE_SAMESITE_NAME" /> se tratarán como si tuvieran "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" y las cookies "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" no necesitarán tener el atributo "<ph name="ATTRIBUTE_SECURE_NAME" />". Además, se omitirá la comparación de esquemas cuando se evalúe si dos sitios web son iguales. Para ver la descripción completa, consulta https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Si no se define esta política, el comportamiento predeterminado de <ph name="ATTRIBUTE_SAMESITE_NAME" /> para las cookies dependerá de la configuración personal del usuario para las funciones <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> y <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />, que puede definirse mediante una prueba pública, o bien habilitando o inhabilitando el indicador <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> o <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />, respectivamente.</translation>
 <translation id="5848438019586925019">El algoritmo para generar pares de claves.</translation>
 <translation id="585270638818921943">Evitar que el usuario utilice aplicaciones Android de fuentes que no son de confianza</translation>
 <translation id="5859344336338527083">Si se define esta política, se especificarán las URL que pueden instalar extensiones, aplicaciones y temas. Antes de la versión 21 de <ph name="PRODUCT_NAME" />, los usuarios podían hacer clic en un enlace a un archivo .crx y <ph name="PRODUCT_NAME" /> les ofrecería la opción de instalar el archivo después de mostrar algunas advertencias. A continuación, esos archivos debían descargarse y arrastrarse a la página de configuración de <ph name="PRODUCT_NAME" />. Esta opción permite que determinadas URL sigan utilizando el proceso de instalación anterior, que era más sencillo.
diff --git a/components/policy/resources/policy_templates_fr.xtb b/components/policy/resources/policy_templates_fr.xtb
index 5ddc76b..8d9e428 100644
--- a/components/policy/resources/policy_templates_fr.xtb
+++ b/components/policy/resources/policy_templates_fr.xtb
@@ -3661,9 +3661,6 @@
       Si cette règle est désactivée ou qu'elle n'est pas configurée, le mode avancé de recharge de la batterie est désactivé.
 
       Les utilisateurs ne peuvent pas modifier ce paramètre.</translation>
-<translation id="5845686745936515940">Permet de rétablir l'ancien comportement <ph name="ATTRIBUTE_SAMESITE_NAME" /> pour tous les cookies. Si vous rétablissez l'ancien comportement, les cookies dont la valeur de l'attribut <ph name="ATTRIBUTE_SAMESITE_NAME" /> n'est pas spécifiée sont traités comme si la valeur "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" était définie. De plus, ceux dont l'attribut a pour valeur "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" n'exigent plus que la valeur de l'attribut "<ph name="ATTRIBUTE_SECURE_NAME" />" soit spécifiée. Enfin, les schémas ne sont pas non plus comparés pour déterminer si deux sites sont identiques ou non. Pour obtenir une description complète, consultez la page https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Lorsque cette règle n'est pas configurée, le comportement <ph name="ATTRIBUTE_SAMESITE_NAME" /> par défaut des cookies dépend de la configuration personnelle de l'utilisateur concernant les fonctionnalités <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> et <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />, qui peut être définie lors d'un test, ou par l'activation ou la désactivation des indicateurs <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> ou <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />, respectivement.</translation>
 <translation id="5848438019586925019">Algorithme pour la génération de paires de clés.</translation>
 <translation id="585270638818921943">Empêche l'utilisateur de se servir d'applications Android provenant de sources non approuvées</translation>
 <translation id="5859344336338527083">Permet de déterminer quelles URL peuvent installer des extensions, des applications et des thèmes. Avant la version 21 de <ph name="PRODUCT_NAME" />, les utilisateurs pouvaient cliquer sur un lien qui renvoyait vers un fichier *.crx, et <ph name="PRODUCT_NAME" /> leur proposait d'installer ce fichier, tout en affichant d'abord quelques avertissements. Depuis, les fichiers de ce type doivent être téléchargés et glissés vers la page des paramètres <ph name="PRODUCT_NAME" />. Cette règle permet d'appliquer à des URL spécifiques l'ancienne procédure d'installation, plus facile à suivre.
diff --git a/components/policy/resources/policy_templates_id.xtb b/components/policy/resources/policy_templates_id.xtb
index fd5970c..8097973e 100644
--- a/components/policy/resources/policy_templates_id.xtb
+++ b/components/policy/resources/policy_templates_id.xtb
@@ -3688,9 +3688,6 @@
       Jika kebijakan disetel ke Nonaktif atau tidak disetel, mode pengisian daya baterai lanjutan akan dinonaktifkan.
 
       Pengguna tidak dapat mengubah setelan ini.</translation>
-<translation id="5845686745936515940">Mengizinkan Anda mengembalikan semua cookie ke perilaku <ph name="ATTRIBUTE_SAMESITE_NAME" /> lama. Pengembalian ke perilaku lama akan menyebabkan cookie yang tidak menentukan atribut <ph name="ATTRIBUTE_SAMESITE_NAME" /> dianggap sebagai "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />", menghapus persyaratan bagi cookie "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" untuk membawa atribut "<ph name="ATTRIBUTE_SECURE_NAME" />", dan melewati perbandingan skema saat evaluasi jika dua situs adalah situs yang sama. Lihat penjelasan lengkapnya di https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Jika kebijakan ini tidak disetel, perilaku <ph name="ATTRIBUTE_SAMESITE_NAME" /> default bagi cookie akan bergantung pada konfigurasi pribadi pengguna untuk fitur <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, fitur <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" />, dan fitur <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> yang dapat disetel berdasarkan uji coba lapangan atau dengan mengaktifkan atau menonaktifkan tanda <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, tanda <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" />, atau tanda <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />, secara berurutan.</translation>
 <translation id="5848438019586925019">Algoritme untuk pembuatan pasangan kunci.</translation>
 <translation id="585270638818921943">Cegah pengguna menggunakan aplikasi Android dari sumber yang tidak tepercaya</translation>
 <translation id="5859344336338527083">Menyetel kebijakan akan menentukan URL mana yang dapat menginstal ekstensi, aplikasi, dan tema. Sebelum <ph name="PRODUCT_NAME" /> 21, pengguna dapat mengklik link ke file *.crx, dan <ph name="PRODUCT_NAME" /> akan menawarkan untuk menginstal file setelah menampilkan beberapa peringatan. Setelah itu, file tersebut harus didownload dan ditarik ke halaman setelan <ph name="PRODUCT_NAME" />. Setelan ini memungkinkan URL tertentu menggunakan alur penginstalan lama yang lebih mudah.
diff --git a/components/policy/resources/policy_templates_it.xtb b/components/policy/resources/policy_templates_it.xtb
index 8d20530..540eb880 100644
--- a/components/policy/resources/policy_templates_it.xtb
+++ b/components/policy/resources/policy_templates_it.xtb
@@ -3655,9 +3655,6 @@
       Se il criterio viene impostato su Disattivato o se non viene configurato, la modalità di ricarica avanzata della batteria rimane disabilitata.
 
       Gli utenti non possono modificare questa impostazione.</translation>
-<translation id="5845686745936515940">Ti consente di ripristinare il comportamento <ph name="ATTRIBUTE_SAMESITE_NAME" /> precedente per tutti i cookie. Se ripristini il comportamento precedente, i cookie per cui non è specificato un attributo <ph name="ATTRIBUTE_SAMESITE_NAME" /> vengono considerati come se avessero il valore "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />"; viene rimosso il requisito che richiede che i cookie "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" abbiano l'attributo "<ph name="ATTRIBUTE_SECURE_NAME" />" e viene ignorato il confronto tra schemi nel valutare se due siti sono stesso sito. Per una descrizione completa, visita la pagina https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Se questo criterio non viene impostato, il comportamento <ph name="ATTRIBUTE_SAMESITE_NAME" /> predefinito per i cookie dipenderà dalla configurazione personale dell'utente per la funzionalità <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, la funzionalità <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" />, e la funzionalità <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />, che potrebbero essere impostate in base a una prova pubblica o tramite l'attivazione o disattivazione rispettivamente dei flag <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> o <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />.</translation>
 <translation id="5848438019586925019">L'algoritmo per la generazione di coppie di chiavi.</translation>
 <translation id="585270638818921943">Impedisci all'utente di usare app Android di fonti non attendibili</translation>
 <translation id="5859344336338527083">Impostare il criterio specifica quali URL sono autorizzati a installare estensioni, app e temi. Prima di <ph name="PRODUCT_NAME" /> 21, gli utenti potevano fare clic su un link a un file *.crx e <ph name="PRODUCT_NAME" /> avrebbe proposto di installare il file dopo alcuni avvisi. Successivamente, tali file devono essere scaricati e trascinati nella pagina delle impostazioni di <ph name="PRODUCT_NAME" />. Questa impostazione consente a URL specifici di utilizzare il precedente flusso di installazione semplificato.
diff --git a/components/policy/resources/policy_templates_ja.xtb b/components/policy/resources/policy_templates_ja.xtb
index 19d1cb2..85ee586 100644
--- a/components/policy/resources/policy_templates_ja.xtb
+++ b/components/policy/resources/policy_templates_ja.xtb
@@ -3560,9 +3560,6 @@
       このポリシーを無効に設定するか未設定のままにした場合、詳細なバッテリー充電モードは無効になります。
 
       ユーザーはこの設定を変更できません。</translation>
-<translation id="5845686745936515940">すべての Cookie を以前の <ph name="ATTRIBUTE_SAMESITE_NAME" /> 動作に戻します。以前の動作に戻すと、<ph name="ATTRIBUTE_SAMESITE_NAME" /> 属性のない Cookie は「<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />」が指定されたものとして扱われます。また、「<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />」の Cookie に「<ph name="ATTRIBUTE_SECURE_NAME" />」属性は必須ではなくなります。さらに、2 つのサイトが同一サイトかどうかを評価する際に、スキーム比較がスキップされます。詳細については https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies をご覧ください。
-
-          このポリシーを設定しない場合、Cookie のデフォルトの <ph name="ATTRIBUTE_SAMESITE_NAME" /> 動作は、<ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> 機能、<ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 機能、<ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> 機能に対するユーザーの個人設定(公開テストで、またはそれぞれ <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> フラグ、<ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> フラグ、<ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> フラグを有効か無効にすることで設定される)によって決まります。</translation>
 <translation id="5848438019586925019">鍵ペアの生成に使用するアルゴリズムです。</translation>
 <translation id="585270638818921943">信頼できない提供元の Android アプリの使用をユーザーに許可しない</translation>
 <translation id="5859344336338527083">このポリシーを設定することで、どの URL から拡張機能、アプリ、テーマのインストールを許可するかを指定できます。<ph name="PRODUCT_NAME" /> 21 より前では、*.crx ファイルのリンクをクリックすると、いくつかの警告が表示された後、<ph name="PRODUCT_NAME" /> によりファイルのインストールを申し出るメッセージが表示されました。それ以降のバージョンでは、このようなファイルは、ダウンロードしてから <ph name="PRODUCT_NAME" /> の設定ページにドラッグする必要があります。この設定を利用することで、特定の URL に以前の簡単なインストール フローを適用できます。
diff --git a/components/policy/resources/policy_templates_ko.xtb b/components/policy/resources/policy_templates_ko.xtb
index 5901036f..5f5f6229 100644
--- a/components/policy/resources/policy_templates_ko.xtb
+++ b/components/policy/resources/policy_templates_ko.xtb
@@ -3683,9 +3683,6 @@
       정책을 사용 중지하거나 설정하지 않으면 고급 배터리 충전 모드가 사용 중지됩니다.
 
       사용자가 이 설정을 변경할 수 없습니다.</translation>
-<translation id="5845686745936515940">모든 쿠키를 기존 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 동작으로 되돌릴 수 있습니다. 기존 동작으로 되돌리면 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 속성을 지정하지 않은 쿠키가 '<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />'인 것처럼 처리되고 '<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />' 쿠키가 '<ph name="ATTRIBUTE_SECURE_NAME" />' 속성을 전달하지 않아도 되며, 두 사이트가 동일한 사이트인지 평가할 때 스킴 비교를 건너뜁니다. https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies에서 전체 설명을 확인하세요.
-
-          정책을 설정하지 않으면 쿠키의 기본 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 동작은 <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> 기능, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 기능, <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> 기능의 사용자 개인 구성에 따라 달라지며, 이러한 구성은 공개 실험에서 또는 <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> 플래그, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 플래그, <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> 플래그를 각각 사용 설정 또는 사용 중지하여 설정할 수 있습니다.</translation>
 <translation id="5848438019586925019">키 쌍 생성을 위한 알고리즘입니다.</translation>
 <translation id="585270638818921943">사용자가 신뢰할 수 없는 출처의 Android 앱을 사용하는 것을 방지</translation>
 <translation id="5859344336338527083">정책을 설정하여 확장 프로그램, 앱, 테마를 설치할 수 있는 URL을 지정합니다. <ph name="PRODUCT_NAME" /> 21 이전에는 사용자가 *.crx 파일 링크를 클릭하면 <ph name="PRODUCT_NAME" />에서 몇 가지 경고 후 파일을 설치하도록 허용했습니다. 이후에는 파일을 다운로드하여 <ph name="PRODUCT_NAME" /> 설정 페이지로 드래그해야 합니다. 이 설정을 사용하면 특정 URL에서 더 간편한 기존의 설치 과정을 따를 수 있습니다.
diff --git a/components/policy/resources/policy_templates_nl.xtb b/components/policy/resources/policy_templates_nl.xtb
index ab2d5f99..a7f21bb 100644
--- a/components/policy/resources/policy_templates_nl.xtb
+++ b/components/policy/resources/policy_templates_nl.xtb
@@ -3635,9 +3635,6 @@
       Als je het beleid niet toepast of niet instelt, blijft de geavanceerde batterijoplaadmodus uit.
 
 Gebruikers kunnen deze instelling niet wijzigen.</translation>
-<translation id="5845686745936515940">Hiermee kun je alle cookies terugzetten op het verouderde gedrag van <ph name="ATTRIBUTE_SAMESITE_NAME" />. Als je het verouderde gedrag terugzet, worden cookies waarin geen <ph name="ATTRIBUTE_SAMESITE_NAME" />-kenmerk is opgegeven, als <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" /> behandeld en wordt de vereiste weggenomen dat cookies van <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" /> het kenmerk <ph name="ATTRIBUTE_SECURE_NAME" /> bevatten. De schemavergelijking wordt overgeslagen tijdens de controle of twee sites dezelfde site zijn. Zie https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies voor een volledige beschrijving.
-
-          Als je dit beleid niet instelt, is het standaardgedrag van <ph name="ATTRIBUTE_SAMESITE_NAME" /> voor cookies afhankelijk van de persoonlijke configuratie van de gebruiker voor de functies <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> en <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />. Deze functies kunnen worden ingesteld via een online test of door de markering <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> of <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> aan of uit te zetten.</translation>
 <translation id="5848438019586925019">Het algoritme voor het genereren van sleutelparen.</translation>
 <translation id="585270638818921943">Voorkomen dat de gebruiker Android-apps van niet-vertrouwde bronnen gebruikt</translation>
 <translation id="5859344336338527083">Als je dit beleid instelt, kun je opgeven welke URL's extensies, apps en thema's mogen installeren. Vóór <ph name="PRODUCT_NAME" /> 21 konden gebruikers op een link naar een *.crx-bestand klikken en bood <ph name="PRODUCT_NAME" /> aan het bestand te installeren na een aantal waarschuwingen. Sindsdien moeten bestanden worden gedownload en naar de instellingenpagina van <ph name="PRODUCT_NAME" /> worden gesleept. Met deze instelling kunnen specifieke URL's het oude, eenvoudigere installatieproces gebruiken.
diff --git a/components/policy/resources/policy_templates_pt-BR.xtb b/components/policy/resources/policy_templates_pt-BR.xtb
index 9758a3c1..8c2849f8 100644
--- a/components/policy/resources/policy_templates_pt-BR.xtb
+++ b/components/policy/resources/policy_templates_pt-BR.xtb
@@ -3663,9 +3663,6 @@
       Se a política for definida como "Desativada" ou não for definida, o modo avançado de carregamento da bateria ficará desativado.
 
       Os usuários não poderão mudar essa configuração.</translation>
-<translation id="5845686745936515940">Permite reverter todos os cookies para o comportamento <ph name="ATTRIBUTE_SAMESITE_NAME" /> legado. A reversão para o comportamento legado faz com que os cookies que não especificam um atributo <ph name="ATTRIBUTE_SAMESITE_NAME" /> sejam tratados como <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />, remove o requisito para cookies <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" /> executarem o atributo <ph name="ATTRIBUTE_SECURE_NAME" /> e pula a comparação do esquema ao avaliar se dois sites são o mesmo. Para ver uma descrição completa, consulte https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies (em inglês).
-
-          Quando essa política não é definida, o comportamento <ph name="ATTRIBUTE_SAMESITE_NAME" /> padrão para cookies depende da configuração pessoal do usuário para os recursos <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> e <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />, que podem ser definidos por um teste de campo, ou ativando e desativando as sinalizações <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> ou <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />, respectivamente.</translation>
 <translation id="5848438019586925019">O algoritmo para gerar pares de chaves.</translation>
 <translation id="585270638818921943">Impede o uso de apps Android de fontes não confiáveis</translation>
 <translation id="5859344336338527083">Se definida, a política especificará os URLs que podem instalar extensões, apps e temas. Antes do <ph name="PRODUCT_NAME" /> 21, os usuários podiam clicar em um link para um arquivo *.crx e o <ph name="PRODUCT_NAME" /> se oferecia para instalar o arquivo após alguns avisos. Depois dessa versão, esses arquivos precisam ser transferidos por download e arrastados para a página de configurações do <ph name="PRODUCT_NAME" />. Essa configuração permite que URLs específicos utilizem o fluxo de instalação antigo e mais simples.
diff --git a/components/policy/resources/policy_templates_ru.xtb b/components/policy/resources/policy_templates_ru.xtb
index aa67873e..27c024a 100644
--- a/components/policy/resources/policy_templates_ru.xtb
+++ b/components/policy/resources/policy_templates_ru.xtb
@@ -3653,9 +3653,6 @@
       Если правило отключено или не настроено, расширенный режим зарядки батареи использоваться не будет.
 
       Пользователи не могут изменить эту настройку.</translation>
-<translation id="5845686745936515940">Позволяет восстановить ранее применявшееся поведение для всех файлов cookie с атрибутом <ph name="ATTRIBUTE_SAMESITE_NAME" />. В этом случае файлы cookie, в которых не указан атрибут <ph name="ATTRIBUTE_SAMESITE_NAME" />, будут обрабатываться как файлы с атрибутом <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />. Кроме того, требование о наличии атрибута <ph name="ATTRIBUTE_SECURE_NAME" /> в файлах cookie с атрибутом <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" /> будет снято, а сравнение протоколов при оценке двух одинаковых сайтов будет пропущено. Полное описание правила приведено здесь: https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Если правило не настроено, поведение атрибута <ph name="ATTRIBUTE_SAMESITE_NAME" /> по умолчанию для файлов cookie будет зависеть от пользовательских настроек функций <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> и <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />, которые можно задать с помощью экспериментальных функций или путем включения или отключения параметра <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> или <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> соответственно.</translation>
 <translation id="5848438019586925019">Алгоритм генерации пары ключей.</translation>
 <translation id="585270638818921943">Запретить использование приложений для Android из ненадежных источников</translation>
 <translation id="5859344336338527083">Правило позволяет указывать URL страниц, с которых пользователям разрешается устанавливать расширения, приложения и темы. До выпуска <ph name="PRODUCT_NAME" /> 21 пользователю достаточно было перейти по ссылке на файл CRX и пропустить несколько предупреждений <ph name="PRODUCT_NAME" />. Теперь такие файлы нужно скачивать и перетаскивать на страницу настроек<ph name="PRODUCT_NAME" />. Это правило позволяет указывать список URL, для которых будет разрешена прежняя, более простая процедура установки.
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb
index 732fcec..c9199838 100644
--- a/components/policy/resources/policy_templates_th.xtb
+++ b/components/policy/resources/policy_templates_th.xtb
@@ -3628,9 +3628,6 @@
       การตั้งค่านโยบายเป็น "ปิดใช้" หรือไม่ตั้งค่าจะทำให้โหมดการชาร์จแบตเตอรี่ขั้นสูงปิดอยู่เสมอ
 
       ผู้ใช้จะเปลี่ยนการตั้งค่านี้ไม่ได้</translation>
-<translation id="5845686745936515940">อนุญาตให้คุณเปลี่ยนคุกกี้ทั้งหมดกลับไปใช้ลักษณะการทำงาน <ph name="ATTRIBUTE_SAMESITE_NAME" /> เดิมได้ การเปลี่ยนกลับไปใช้ลักษณะการทำงานเดิมทำให้คุกกี้ที่ไม่ได้ระบุแอตทริบิวต์ <ph name="ATTRIBUTE_SAMESITE_NAME" /> ได้รับการดำเนินการเหมือนกับเป็น "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />", นำข้อกำหนดที่คุกกี้ "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" ต้องมีแอตทริบิวต์ "<ph name="ATTRIBUTE_SECURE_NAME" />" ออกไป และข้ามการเปรียบเทียบสกีมเมื่อประเมินว่าเว็บไซต์ 2 แห่งเป็นเว็บไซต์เดียวกันหรือไม่ ดูคำอธิบายแบบเต็มใน https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies
-
-          เมื่อไม่ได้ตั้งค่านโยบายนี้ ลักษณะการทำงาน <ph name="ATTRIBUTE_SAMESITE_NAME" /> ที่เป็นค่าเริ่มต้นของคุกกี้จะขึ้นอยู่กับการกำหนดค่าส่วนตัวของผู้ใช้สำหรับฟีเจอร์ <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, ฟีเจอร์ <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> และฟีเจอร์ <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> ซึ่งอาจมีการตั้งค่าโดยการทดสอบในวงจำกัด หรือโดยการเปิดหรือปิดใช้แฟล็ก <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, แฟล็ก <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> หรือแฟล็ก <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> ตามลำดับ</translation>
 <translation id="5848438019586925019">อัลกอริทึมสำหรับการสร้างคู่คีย์</translation>
 <translation id="585270638818921943">ป้องกันไม่ให้ผู้ใช้ใช้แอป Android จากแหล่งที่มาที่ไม่น่าเชื่อถือ</translation>
 <translation id="5859344336338527083">การตั้งค่านโยบายจะระบุ URL ที่ติดตั้งส่วนขยาย แอป และธีมได้ ก่อน <ph name="PRODUCT_NAME" /> 21 ผู้ใช้คลิกลิงก์เพื่อไปยังไฟล์ *.crx ได้ จากนั้น <ph name="PRODUCT_NAME" /> จะเสนอให้ติดตั้งไฟล์หลังจากแสดงคำเตือน 2-3 รายการ แต่ในเวอร์ชันต่อมา จะต้องมีการดาวน์โหลดไฟล์ดังกล่าวและลากไปที่หน้าการตั้งค่า <ph name="PRODUCT_NAME" /> การตั้งค่านี้อนุญาตให้บาง URL มีขั้นตอนการติดตั้งแบบเก่าแต่ใช้งานง่ายกว่าได้
diff --git a/components/policy/resources/policy_templates_tr.xtb b/components/policy/resources/policy_templates_tr.xtb
index 95a2dc1a..ce32360 100644
--- a/components/policy/resources/policy_templates_tr.xtb
+++ b/components/policy/resources/policy_templates_tr.xtb
@@ -3649,9 +3649,6 @@
       Politika, Devre Dışı değerine ayarlanırsa gelişmiş pil şarj modu kapalı olur.
 
       Kullanıcılar bu ayarı değiştiremez.</translation>
-<translation id="5845686745936515940">Tüm çerezleri eski <ph name="ATTRIBUTE_SAMESITE_NAME" /> davranışına geri döndürmenize olanak tanır. Eski davranışa geri dönmek, <ph name="ATTRIBUTE_SAMESITE_NAME" /> özelliği belirtmeyen çerezlerin "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" gibi değerlendirilmesine neden olur, "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" çerezlerinin "<ph name="ATTRIBUTE_SECURE_NAME" />" özelliğini taşıma şartını ortadan kaldırır ve iki sitenin aynı URL'yi paylaşması durumunda, değerlendirirken şema karşılaştırmasını atlar. Tam açıklama için https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies adresine bakın.
-
-          Bu politika ayarlanmadığında, çerezler için varsayılan <ph name="ATTRIBUTE_SAMESITE_NAME" /> davranışı, kullanıcının <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> özelliğini kişisel yapılandırmasına, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> özelliğine ve saha denemesi tarafından ayarlanan veya sırasıyla <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> işaretinin, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> işaretinin ya da <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> işaretinin etkinleştirilmesi veya devre dışı bırakılması ile ayarlanan <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> özelliğine bağlıdır.</translation>
 <translation id="5848438019586925019">Anahtar çifti oluşturmak için kullanılan algoritma.</translation>
 <translation id="585270638818921943">Kullanıcının güvenilmeyen kaynaklardan Android uygulamaları kullanmasını engelle</translation>
 <translation id="5859344336338527083">Politikayı ayarlamak uzantı, uygulama ve tema yükleyebilecek URL'leri belirtir. <ph name="PRODUCT_NAME" /> 21 sürümünden önce, kullanıcılar bir *.crx dosyası bağlantısını tıklayarak <ph name="PRODUCT_NAME" /> ürününün birkaç uyarıdan sonra dosyayı yüklemesini sağlayabiliyordu. Daha sonra, bu tür dosyaların indirilip <ph name="PRODUCT_NAME" /> ayarları sayfasına sürüklenmesi zorunlu hale getirilmiştir. Bu ayar, belirli URL'lerin eski, daha kolay yükleme akışına sahip olmasına olanak tanır.
diff --git a/components/policy/resources/policy_templates_uk.xtb b/components/policy/resources/policy_templates_uk.xtb
index 634aebd..a282bf64 100644
--- a/components/policy/resources/policy_templates_uk.xtb
+++ b/components/policy/resources/policy_templates_uk.xtb
@@ -3685,9 +3685,6 @@
       Якщо це правило деактивовано або не налаштовано, режим покращеного заряджання вимкнено.
 
       Користувачі не можуть змінювати це налаштування.</translation>
-<translation id="5845686745936515940">Дозволяє налаштувати застарілу поведінку <ph name="ATTRIBUTE_SAMESITE_NAME" /> для всіх файлів cookie. Якщо повернутися до застарілої поведінки, файли cookie, у яких не вказано атрибут <ph name="ATTRIBUTE_SAMESITE_NAME" />, вважатимуться <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />, вимога, згідно з якою файли cookie <ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" /> повинні мати атрибут <ph name="ATTRIBUTE_SECURE_NAME" />, скасується, а схема порівняння під час перевірки наявності атрибута SameSite для двох сайтів пропускатиметься. Повний опис можна переглянути на сторінці https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Якщо це правило не налаштовано, поведінка <ph name="ATTRIBUTE_SAMESITE_NAME" /> за умовчанням для файлів cookie залежатиме від того, як користувач налаштував функції <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> і <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />. Це можна зробити на етапі тестування або поставивши чи знявши прапорець біля опцій <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> або <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> відповідно.</translation>
 <translation id="5848438019586925019">Алгоритм створення пар ключів.</translation>
 <translation id="585270638818921943">Заборонити користувачеві завантажувати додатки для Android із ненадійних джерел</translation>
 <translation id="5859344336338527083">Налаштування цього правила визначають URL-адреси, з яких можна встановлювати розширення, додатки й теми. У попередніх версіях (до <ph name="PRODUCT_NAME" /> 21) користувачі могли натиснути посилання на файл *.crx і після кількох застережень установити його в <ph name="PRODUCT_NAME" />. У новіших версіях такі файли потрібно завантажувати й перетягувати на сторінку налаштувань <ph name="PRODUCT_NAME" />. Цей параметр дозволяє старіший і простіший процес встановлення з певних URL-адрес.
diff --git a/components/policy/resources/policy_templates_vi.xtb b/components/policy/resources/policy_templates_vi.xtb
index f81a014..19be5dc8 100644
--- a/components/policy/resources/policy_templates_vi.xtb
+++ b/components/policy/resources/policy_templates_vi.xtb
@@ -3691,9 +3691,6 @@
       Nếu bạn đặt thành Tắt hoặc không đặt chính sách này, chế độ sạc pin nâng cao sẽ luôn tắt.
 
       Người dùng không thể quản lý tùy chọn cài đặt này.</translation>
-<translation id="5845686745936515940">Cho phép bạn đưa tất cả cookie về hành vi <ph name="ATTRIBUTE_SAMESITE_NAME" /> cũ. Khi quay lại về hành vi cũ, cookie sẽ không chỉ định việc xử lý thuộc tính <ph name="ATTRIBUTE_SAMESITE_NAME" /> như thể là "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" và cookie "<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />" không cần phải mang thuộc tính "<ph name="ATTRIBUTE_SECURE_NAME" />", đồng thời hệ thống sẽ bỏ qua quy trình so sánh lược đồ khi đánh giá liệu 2 trang web có phải là một hay không. Để xem thông tin chi tiết, vui lòng truy cập https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies.
-
-          Nếu bạn không đặt chính sách này, thì hành vi <ph name="ATTRIBUTE_SAMESITE_NAME" /> mặc định đối với các cookie sẽ phụ thuộc vào cấu hình cá nhân của người dùng cho tính năng <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> và <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" />. Bạn có thể đặt các tính năng này trong giai đoạn thực nghiệm hoặc bằng cách bật/tắt lần lượt cờ <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />, <ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> hay <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" />.</translation>
 <translation id="5848438019586925019">Thuật toán để tạo cặp khóa.</translation>
 <translation id="585270638818921943">Ngăn người dùng sử dụng các ứng dụng Android từ những nguồn không tin cậy</translation>
 <translation id="5859344336338527083">Nếu bạn đặt chính sách này, thì hệ thống sẽ chỉ định những URL nào có thể cài đặt tiện ích, ứng dụng và giao diện. Trước <ph name="PRODUCT_NAME" /> 21, người dùng có thể nhấp vào một đường liên kết tới tệp *.crx và <ph name="PRODUCT_NAME" /> sẽ đề xuất cài đặt tệp này sau một vài cảnh báo. Về sau, người dùng phải tải các tệp này xuống và kéo vào trang cài đặt <ph name="PRODUCT_NAME" />. Tùy chọn cài đặt này cho phép các URL cụ thể thực hiện theo quy trình cài đặt cũ, dễ dàng hơn.
diff --git a/components/policy/resources/policy_templates_zh-CN.xtb b/components/policy/resources/policy_templates_zh-CN.xtb
index 06523bf..d9d5db6 100644
--- a/components/policy/resources/policy_templates_zh-CN.xtb
+++ b/components/policy/resources/policy_templates_zh-CN.xtb
@@ -3629,9 +3629,6 @@
       如果此政策已停用或未设置,高级电池充电模式会保持关闭状态。
 
       用户无法更改此设置。</translation>
-<translation id="5845686745936515940">此政策让您能够将所有 Cookie 都恢复为旧版 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 行为。恢复为旧版行为会导致未指定 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 属性的 Cookie 被当作“<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />”Cookie 来处理,撤消“<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />”Cookie 必须附带“<ph name="ATTRIBUTE_SECURE_NAME" />”属性的要求,并且在评估两个网站是否为同一个网站时会跳过协议比较。如需查看完整说明,请参阅 https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies。
-
-          如果未设置此政策,Cookie 的默认 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 行为将取决于用户针对 <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> 功能、<ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 功能和 <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> 功能(这些功能可通过现场试验来设置,也可通过启用或停用这些功能分别对应的 <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" /> 标记、<ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 标记或 <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> 标记来设置)指定的个人配置。</translation>
 <translation id="5848438019586925019">用于生成密钥对的算法。</translation>
 <translation id="585270638818921943">禁止用户使用来源不受信任的 Android 应用</translation>
 <translation id="5859344336338527083">通过设置此政策,您可以指定哪些网址可安装扩展程序、应用和主题背景。在 <ph name="PRODUCT_NAME" /> 21 以前,用户可以点击指向 *.crx 文件的链接,<ph name="PRODUCT_NAME" /> 虽然会显示一些警告,但仍会让用户安装该文件。但从 21 版开始,用户必须下载此类文件并将其拖动到 <ph name="PRODUCT_NAME" /> 的设置页面中。此设置可允许特定网址采用较简便的旧安装流程。
diff --git a/components/policy/resources/policy_templates_zh-TW.xtb b/components/policy/resources/policy_templates_zh-TW.xtb
index 602c4e0..3652269 100644
--- a/components/policy/resources/policy_templates_zh-TW.xtb
+++ b/components/policy/resources/policy_templates_zh-TW.xtb
@@ -3615,9 +3615,6 @@
       如果將這項政策設為停用或不設定,系統會將進階充電模式保持關閉。
 
       使用者無法變更這項設定。</translation>
-<translation id="5845686745936515940">允許你將所有 Cookie 還原成舊版的 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 行為。還原成舊版的行為會導致系統將未指定 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 屬性的 Cookie 視為「<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />」,並移除「<ph name="ATTRIBUTE_VALUE_SAMESITE_NONE" />」Cookie 必須帶有「<ph name="ATTRIBUTE_SECURE_NAME" />」屬性的要求。此外,這也會讓系統在評估兩個網站是否相同時,略過網址架構的比較。如需完整說明,請參閱 https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies。
-
-          如果不設定這項政策,系統對於 Cookie 所採取的預設 <ph name="ATTRIBUTE_SAMESITE_NAME" /> 行為會取決於使用者對於 <ph name="FEATURE_NAME_SAMESITE_BY_DEFAULT_COOKIES" />、<ph name="FEATURE_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 和 <ph name="FEATURE_NAME_SCHEMEFUL_SAME_SITE" /> 功能的個人配置。使用者可以透過實際測試,或是分別啟用或停用 <ph name="FLAG_NAME_SAMESITE_BY_DEFAULT_COOKIES" />、<ph name="FLAG_NAME_SAMESITE_NONE_MUST_BE_SECURE" /> 或 <ph name="FLAG_NAME_SCHEMEFUL_SAME_SITE" /> 旗標,來設定這項功能的個人配置。</translation>
 <translation id="5848438019586925019">用於產生金鑰組的演算法。</translation>
 <translation id="585270638818921943">禁止使用者使用來源不受信任的 Android 應用程式</translation>
 <translation id="5859344336338527083">你可以透過這項政策,指定可安裝擴充功能、應用程式和主題的網址。在 <ph name="PRODUCT_NAME" /> 21 以前的版本中,使用者只要點選 *.crx 檔案的連結,<ph name="PRODUCT_NAME" /> 就會在顯示幾則警告訊息後,詢問使用者是否要安裝該檔案。在後續版本中,使用者則必須先下載這類檔案,再將檔案拖曳至 <ph name="PRODUCT_NAME" /> 設定頁面中。透過這項設定,你可以允許特定網址使用較簡易的舊式安裝流程。
diff --git a/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc b/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
index 895823b..3d734f8 100644
--- a/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
+++ b/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
@@ -44,6 +44,7 @@
 #include "net/cert/x509_certificate.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_context.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 
 namespace {
@@ -322,7 +323,6 @@
     return DENIED;
 
   base::DictionaryValue* dict;  // Owned by value
-  int policy_decision;
   bool success = value->GetAsDictionary(&dict);
   DCHECK(success);
 
@@ -336,12 +336,12 @@
     return DENIED;
   }
 
-  success = cert_error_dict->GetIntegerWithoutPathExpansion(GetKey(cert, error),
-                                                            &policy_decision);
+  absl::optional<int> policy_decision =
+      cert_error_dict->FindIntKey(GetKey(cert, error));
 
   // If a policy decision was successfully retrieved and it's a valid value of
   // ALLOWED, return the valid value. Otherwise, return DENIED.
-  if (success && policy_decision == ALLOWED)
+  if (policy_decision.has_value() && policy_decision.value() == ALLOWED)
     return ALLOWED;
 
   return DENIED;
diff --git a/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc b/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
index 511a427..6e1d004 100644
--- a/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
+++ b/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
@@ -19,9 +19,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
-// TODO(nyquist): Change to optimization target for segmentation once available.
 const auto kOptimizationTarget = optimization_guide::proto::OptimizationTarget::
-    OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD;
+    OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
 }  // namespace
 
 namespace segmentation_platform {
diff --git a/components/segmentation_platform/internal/scheduler/model_execution_scheduler_unittest.cc b/components/segmentation_platform/internal/scheduler/model_execution_scheduler_unittest.cc
index 3181db7..9d9c58b6 100644
--- a/components/segmentation_platform/internal/scheduler/model_execution_scheduler_unittest.cc
+++ b/components/segmentation_platform/internal/scheduler/model_execution_scheduler_unittest.cc
@@ -17,7 +17,7 @@
 namespace segmentation_platform {
 namespace {
 constexpr auto kTestOptimizationTarget =
-    OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS;
+    OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
 }  // namespace
 
 class MockModelExecutionObserver : public ModelExecutionScheduler::Observer {
diff --git a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
index 103cf7a..4ca027a 100644
--- a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
+++ b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
@@ -90,7 +90,7 @@
 
 TEST_F(SegmentSelectorTest, CheckDiscreteMapping) {
   OptimizationTarget segment_id =
-      OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
   float mapping[][2] = {{0.2, 1}, {0.5, 3}, {0.7, 4}};
   segment_database_->AddDiscreteMapping(segment_id, mapping, 3);
   proto::SegmentInfo* segment_info =
@@ -112,12 +112,12 @@
 
 TEST_F(SegmentSelectorTest, FindBestSegmentFlowWithTwoSegments) {
   OptimizationTarget segment_id =
-      OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
   float mapping[][2] = {{0.2, 1}, {0.5, 3}, {0.7, 4}};
   segment_database_->AddDiscreteMapping(segment_id, mapping, 3);
 
   OptimizationTarget segment_id2 =
-      OptimizationTarget::OPTIMIZATION_TARGET_LANGUAGE_DETECTION;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
   float mapping2[][2] = {{0.3, 1}, {0.4, 4}};
   segment_database_->AddDiscreteMapping(segment_id2, mapping2, 2);
 
@@ -137,7 +137,7 @@
 
 TEST_F(SegmentSelectorTest, NewSegmentResultOverridesThePreviousBest) {
   OptimizationTarget segment_id1 =
-      OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
   float mapping1[][2] = {{0.2, 1}, {0.5, 3}, {0.7, 4}};
   segment_database_->AddDiscreteMapping(segment_id1, mapping1, 3);
 
@@ -155,7 +155,7 @@
 
   // Another model completes execution. The selection should update.
   OptimizationTarget segment_id2 =
-      OptimizationTarget::OPTIMIZATION_TARGET_LANGUAGE_DETECTION;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
   float mapping2[][2] = {{0.3, 1}, {0.4, 4}};
   segment_database_->AddDiscreteMapping(segment_id2, mapping2, 2);
 
@@ -173,7 +173,7 @@
        GetSelectedSegmentReturnsResultFromPreviousSession) {
   // Initialize segment selector. It should read selected segment from prefs.
   OptimizationTarget segment_id0 =
-      OptimizationTarget::OPTIMIZATION_TARGET_LANGUAGE_DETECTION;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
   SelectedSegment from_history(segment_id0);
   EXPECT_CALL(*prefs_, ReadSegmentationResultFromPref())
       .WillRepeatedly(Return(from_history));
@@ -186,7 +186,7 @@
 
   // Add results for a new segment.
   OptimizationTarget segment_id1 =
-      OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS;
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
   float mapping1[][2] = {{0.2, 1}, {0.5, 3}, {0.7, 4}};
   segment_database_->AddDiscreteMapping(segment_id1, mapping1, 3);
 
diff --git a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
index 901a014..40b9646d 100644
--- a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
+++ b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
@@ -50,10 +50,11 @@
 TEST_F(SignalFilterProcessorTest, UserActionRegistrationFlow) {
   std::string kUserActionName1 = "some_action_1";
   segment_database_->AddUserAction(
-      OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS, kUserActionName1);
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB,
+      kUserActionName1);
   std::string kUserActionName2 = "some_action_2";
   segment_database_->AddUserAction(
-      OptimizationTarget::OPTIMIZATION_TARGET_LANGUAGE_DETECTION,
+      OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE,
       kUserActionName2);
 
   std::set<uint64_t> actions;
diff --git a/components/strings/components_strings_af.xtb b/components/strings/components_strings_af.xtb
index bf033ef2..698e231 100644
--- a/components/strings/components_strings_af.xtb
+++ b/components/strings/components_strings_af.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Die bedienersertifikaat bevat 'n swak kriptografiese sleutel.</translation>
 <translation id="1696290444144917273">Bekyk virtuele kaart se besonderhede</translation>
 <translation id="1697532407822776718">Als is nou reg!</translation>
+<translation id="1699570257714336246">Inligting ontbreek</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Hierdie bediener kon nie bewys dat hy <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaat geld kwansuis van môre af. Dit is dalk veroorsaak deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep het.}other{Hierdie bediener kon nie bewys dat hy <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaat geld kwansuis van # dae in die toekoms af. Dit is dalk veroorsaak deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep het.}}</translation>
 <translation id="1710259589646384581">Bedryfstelsel</translation>
diff --git a/components/strings/components_strings_am.xtb b/components/strings/components_strings_am.xtb
index be6a282..f2fe202 100644
--- a/components/strings/components_strings_am.xtb
+++ b/components/strings/components_strings_am.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">የአገልጋይ እውቅና ማረጋገጫው ደካማ የሆነ ባለስውር መረጃ ቁልፍ ነው ያለው።</translation>
 <translation id="1696290444144917273">ምናባዊ የካርድ ዝርዝሮችን ይመልከቱ</translation>
 <translation id="1697532407822776718">በቃ ጨርሰዋል!</translation>
+<translation id="1699570257714336246">መረጃ ይጎድላል</translation>
 <translation id="1703835215927279855">ደብዳቤ</translation>
 <translation id="1706954506755087368">{1,plural, =1{ይህ አገልጋይ <ph name="DOMAIN" /> እንደሆነ ማረጋገጥ አልቻለም፤ የደህንነት ማረጋገጫ እውቅና ማረጋገጫው ከነገ የመጣ ነው ይላል። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።}one{ይህ አገልጋይ <ph name="DOMAIN" /> እንደሆነ ማረጋገጥ አልቻለም፤ የደህንነት ማረጋገጫ እውቅና ማረጋገጫው የወደፊት # ቀንኖች የመጣ ነው ይላል። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።}other{ይህ አገልጋይ <ph name="DOMAIN" /> እንደሆነ ማረጋገጥ አልቻለም፤ የደህንነት ማረጋገጫ እውቅና ማረጋገጫው የወደፊት # ቀንኖች የመጣ ነው ይላል። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።}}</translation>
 <translation id="1710259589646384581">ስርዓተ ክወና</translation>
diff --git a/components/strings/components_strings_ar.xtb b/components/strings/components_strings_ar.xtb
index 5da0a0eb..0c83664f 100644
--- a/components/strings/components_strings_ar.xtb
+++ b/components/strings/components_strings_ar.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">تحتوي شهادة الخادم على مفتاح ترميز ضعيف.</translation>
 <translation id="1696290444144917273">عرض تفاصيل البطاقة الافتراضية</translation>
 <translation id="1697532407822776718">أنت الآن على أتم استعداد.</translation>
+<translation id="1699570257714336246">معلومات غير متوفرة</translation>
 <translation id="1703835215927279855">خطاب</translation>
 <translation id="1706954506755087368">{1,plural, =1{هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ من المفترض أن تبدأ شهادة أمانه من الغد. ربما يكون السبب في ذلك خطأ في الإعداد أو مهاجمًا يعترض اتصالك.}zero{هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ من المفترض أن تبدأ شهادة أمانه خلال # يوم في المستقبل. ربما يكون السبب في ذلك خطأ في الإعداد أو مهاجمًا يعترض اتصالك.}two{هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ من المفترض أن تبدأ شهادة أمانه خلال يومين (#) في المستقبل. ربما يكون السبب في ذلك خطأ في الإعداد أو مهاجمًا يعترض اتصالك.}few{هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ من المفترض أن تبدأ شهادة أمانه خلال # أيام في المستقبل. ربما يكون السبب في ذلك خطأ في الإعداد أو مهاجمًا يعترض اتصالك.}many{هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ من المفترض أن تبدأ شهادة أمانه خلال # يومًا في المستقبل. ربما يكون السبب في ذلك خطأ في الإعداد أو مهاجمًا يعترض اتصالك.}other{هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ من المفترض أن تبدأ شهادة أمانه خلال # يوم في المستقبل. ربما يكون السبب في ذلك خطأ في الإعداد أو مهاجمًا يعترض اتصالك.}}</translation>
 <translation id="1710259589646384581">نظام التشغيل</translation>
diff --git a/components/strings/components_strings_as.xtb b/components/strings/components_strings_as.xtb
index 624efd7..de27fab 100644
--- a/components/strings/components_strings_as.xtb
+++ b/components/strings/components_strings_as.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">ছার্ভাৰ প্ৰমাণপত্ৰখনত এটা দুৰ্বল ক্ৰিপ্টগ্ৰাফিক কী আছে।</translation>
 <translation id="1696290444144917273">ভাৰ্ছুৱেল কাৰ্ডৰ সবিশেষ চাওক</translation>
 <translation id="1697532407822776718">আপুনি সম্পূৰ্ণ সাজু!</translation>
+<translation id="1699570257714336246">তথ্য নাই</translation>
 <translation id="1703835215927279855">লেটাৰ</translation>
 <translation id="1706954506755087368">{1,plural, =1{এই ছাৰ্ভাৰটোৱে এইটোক <ph name="DOMAIN" /> বুলি প্ৰমাণ কৰিব নোৱাৰিলে, ইয়াৰ সুৰক্ষা প্ৰমাণপত্ৰ কাইলৈৰপৰা মান্য হ’লহেঁতেন। কোনো ভুল কনফিগাৰেশ্বনৰ বাবে বা কোনো আক্ৰমণকাৰীয়ে আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে এয়া হ’ব পাৰে।}one{এই ছাৰ্ভাৰটোৱে এইটোক <ph name="DOMAIN" /> বুলি প্ৰমাণ কৰিব নোৱাৰিলে, ইয়াৰ সুৰক্ষা প্ৰমাণপত্ৰ # দিনৰ পিছত মান্য হ’লহেঁতেন। কোনো ভুল কনফিগাৰেশ্বনৰ বাবে বা কোনো আক্ৰমণকাৰীয়ে আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে এয়া হ’ব পাৰে।}other{এই ছাৰ্ভাৰটোৱে এইটোক <ph name="DOMAIN" /> বুলি প্ৰমাণ কৰিব নোৱাৰিলে, ইয়াৰ সুৰক্ষা প্ৰমাণপত্ৰ # দিনৰ পিছত মান্য হ’লহেঁতেন। কোনো ভুল কনফিগাৰেশ্বনৰ বাবে বা কোনো আক্ৰমণকাৰীয়ে আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে এয়া হ’ব পাৰে।}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_az.xtb b/components/strings/components_strings_az.xtb
index 447baeb3..be1b770 100644
--- a/components/strings/components_strings_az.xtb
+++ b/components/strings/components_strings_az.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Server sertifikatının kriptoqrafik açarı zəifdir.</translation>
 <translation id="1696290444144917273">Virtual kart detallarına baxın</translation>
 <translation id="1697532407822776718">Hər şey hazırdır!</translation>
+<translation id="1699570257714336246">Əskik məlumat var</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Bu server <ph name="DOMAIN" /> olduğunu sübut edə bilmədi; böyük ehtimal təhlükəsizlik sertifikatı sabahdan etibarən nəzərdə tutulub. Buna yanlış konfiqurasiya və ya hücumçu tərəfindən bağlantının ələ keçirilməsi səbəb ola bilər.}other{Bu server <ph name="DOMAIN" /> olduğunu sübut edə bilmədi; təhlükəsizlik sertifikatı gələcəkdə # gündən sonra nəzərdə tutulub. Buna yanlış konfiqurasiya və ya hücumçu tərəfindən bağlantının ələ keçirilməsi səbəb ola bilər.}}</translation>
 <translation id="1710259589646384581">OS</translation>
@@ -1719,7 +1720,7 @@
 <translation id="7378594059915113390">Media Nəzarətləri</translation>
 <translation id="7378627244592794276">Xeyr</translation>
 <translation id="7378810950367401542">/</translation>
-<translation id="7386364858855961704">Tətbiq edilə bilməz</translation>
+<translation id="7386364858855961704">Tətbiq olunmur</translation>
 <translation id="7390545607259442187">Kartı Təsdiqləyin</translation>
 <translation id="7392089738299859607">Ünvanı yeniləyin</translation>
 <translation id="7399802613464275309">Təhlükəsizlik Yoxlanışı</translation>
diff --git a/components/strings/components_strings_be.xtb b/components/strings/components_strings_be.xtb
index 08523bd..d66e188 100644
--- a/components/strings/components_strings_be.xtb
+++ b/components/strings/components_strings_be.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">У сертыфіката сервера слабы крыптаграфічны ключ.</translation>
 <translation id="1696290444144917273">Паглядзець рэквізіты віртуальнай карткі</translation>
 <translation id="1697532407822776718">Усё гатова!</translation>
+<translation id="1699570257714336246">Звесткі адсутнічаюць</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Серверу не ўдалося даказаць, што гэта дамен <ph name="DOMAIN" />. Здаецца, яго сертыфікат бяспекі пачынае дзейнічаць з заўтрашняга дня. Прычынай могуць быць няправільныя налады або зламыснік, які спрабуе перахапіць падключэнне.}one{Серверу не ўдалося даказаць, што гэта дамен <ph name="DOMAIN" />. Здаецца, яго сертыфікат бяспекі пачынае дзейнічаць праз # дзень. Прычынай могуць быць няправільныя налады або зламыснік, які спрабуе перахапіць падключэнне.}few{Серверу не ўдалося даказаць, што гэта дамен <ph name="DOMAIN" />. Здаецца, яго сертыфікат бяспекі пачынае дзейнічаць праз # дні. Прычынай могуць быць няправільныя налады або зламыснік, які спрабуе перахапіць падключэнне.}many{Серверу не ўдалося даказаць, што гэта дамен <ph name="DOMAIN" />. Здаецца, яго сертыфікат бяспекі пачынае дзейнічаць праз # дзён. Прычынай могуць быць няправільныя налады або зламыснік, які спрабуе перахапіць падключэнне.}other{Серверу не ўдалося даказаць, што гэта дамен <ph name="DOMAIN" />. Здаецца, яго сертыфікат бяспекі пачынае дзейнічаць праз # дня. Прычынай могуць быць няправільныя налады або зламыснік, які спрабуе перахапіць падключэнне.}}</translation>
 <translation id="1710259589646384581">АС</translation>
diff --git a/components/strings/components_strings_bg.xtb b/components/strings/components_strings_bg.xtb
index 191b01cb..7f4e550 100644
--- a/components/strings/components_strings_bg.xtb
+++ b/components/strings/components_strings_bg.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сертификатът на сървъра съдържа слаб криптографски ключ.</translation>
 <translation id="1696290444144917273">Преглед на данните за виртуалната карта</translation>
 <translation id="1697532407822776718">Готово!</translation>
+<translation id="1699570257714336246">Липсва информация</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Сертификатът му за сигурност е от утре. Това може да се дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака.}other{Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Сертификатът му за сигурност е от # дни в бъдещето. Това може да се дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака.}}</translation>
 <translation id="1710259589646384581">ОС</translation>
diff --git a/components/strings/components_strings_bn.xtb b/components/strings/components_strings_bn.xtb
index 095ca25..7c9dfec 100644
--- a/components/strings/components_strings_bn.xtb
+++ b/components/strings/components_strings_bn.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">সার্ভার সার্টিফিকেটে একটি দুর্বল ক্রিপ্টোগ্রাফিক কী আছে৷</translation>
 <translation id="1696290444144917273">ভার্চুয়াল কার্ডের বিবরণ দেখুন</translation>
 <translation id="1697532407822776718">আপনার সমস্ত সেট আছে!</translation>
+<translation id="1699570257714336246">সম্পূর্ণ তথ্য দেওয়া হয়নি</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{এই সার্ভার যে <ph name="DOMAIN" /> তা এটি প্রমাণ করতে পারেনি; এর নিরাপত্তা সার্টিফিকেটটি আগামীকালের বলে মনে হচ্ছে। কোনও ভুল কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপ্রদানকারী কোনও আক্রমণকারীর কারণে এমনটি হতে পারে।}one{এই সার্ভার যে <ph name="DOMAIN" /> তা এটি প্রমাণ করতে পারেনি; এর নিরাপত্তা সার্টিফিকেটটি আগামী # দিন পরের বলে মনে হচ্ছে। কোনও ভুল কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপ্রদানকারী কোনও আক্রমণকারীর কারণে এমনটি হতে পারে।}other{এই সার্ভার যে <ph name="DOMAIN" /> তা এটি প্রমাণ করতে পারেনি; এর নিরাপত্তা সার্টিফিকেটটি আগামী # দিন পরের বলে মনে হচ্ছে। কোনও ভুল কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপ্রদানকারী কোনও আক্রমণকারীর কারণে এমনটি হতে পারে।}}</translation>
 <translation id="1710259589646384581">OS</translation>
@@ -735,6 +736,7 @@
 <translation id="3631244953324577188">বায়োমেট্রিক্স</translation>
 <translation id="3633738897356909127">Chrome আপডেট করার বোতাম, আপনার Chrome সেটিংসে Chrome আপডেট করতে Enter প্রেস করুন</translation>
 <translation id="3634530185120165534">ট্রে ৫</translation>
+<translation id="3637662659967048211">Google অ্যাকাউন্টে সেভ করুন</translation>
 <translation id="3640766068866876100">Index-4x6-Ext</translation>
 <translation id="3642638418806704195">অ্যাপ্লিকেশন:</translation>
 <translation id="3650584904733503804">বৈধতা যাচাইকরণ সফল হয়েছে</translation>
@@ -1412,6 +1414,7 @@
 <translation id="6106989379647458772"><ph name="PAGE" />-এ ওয়েবপৃষ্ঠাটি অস্থায়ীভাবে ডাউন হয়ে থাকতে পারে অথবা এটি হয়ত একটি নতুন ওয়েব ঠিকানায় স্থায়ীভাবে সরানো হয়েছে।</translation>
 <translation id="6107012941649240045">একে ইস্যু করা হয়েছিল</translation>
 <translation id="610911394827799129"><ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />-এ আপনার Google অ্যাকাউন্টের অন্যান্য ধরনের ব্রাউজিংয়ের ইতিহাস থাকতে পারে</translation>
+<translation id="6113594885686374546">সার্চ করা আবার চালু করতে, সার্চ করা আবার চালু করার বোতাম, Enter প্রেস করুন এবং আপনার Chrome ইতিহাসে প্রাসঙ্গিক অ্যাক্টিভিটি দেখুন</translation>
 <translation id="6116338172782435947">ক্লিপবোর্ডে কপি করা টেক্সট এবং ছবি দেখতে</translation>
 <translation id="6120179357481664955">আপনার UPI আইডি মনে আছে?</translation>
 <translation id="6123290840358279103">ভার্চুয়াল কার্ড দেখুন</translation>
@@ -1486,6 +1489,7 @@
 <translation id="6423385022588644828">এখন থেকে টাচ আইডি ব্যবহার করে আপনার কার্ড আরও দ্রুত কনফার্ম করুন</translation>
 <translation id="6425092077175753609">মেটারিয়াল</translation>
 <translation id="6427730057873428458">গেট ফোল্ড</translation>
+<translation id="6428146287756735566">Chrome ইতিহাসে প্রাসঙ্গিক অ্যাক্টিভিটি দেখতে সার্চ করা আবার চালু করুন</translation>
 <translation id="6428450836711225518">আপনার ফোন নম্বর যাচাই করুন</translation>
 <translation id="6433490469411711332">পরিচিতি তথ্য সম্পাদনা করুন</translation>
 <translation id="6433595998831338502"><ph name="HOST_NAME" /> সংযোগ করতে প্রত্যাখ্যান করেছে।</translation>
@@ -1537,6 +1541,7 @@
 <translation id="6643016212128521049">সাফ করুন</translation>
 <translation id="6645291930348198241">কুকি ও সাইট ডেটা অ্যাক্সেস করার অনুমতি দিন।</translation>
 <translation id="6646269444027925224">{COUNT,plural, =0{কিছুই নয়}=1{১টি সাইট থেকে (আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না)}one{#টি সাইট থেকে (আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না)}other{#টি সাইট থেকে (আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না)}}</translation>
+<translation id="6647197322759179819">আবার চালু করুন</translation>
 <translation id="6648459603387803038">আপনার অ্যাডমিনিস্ট্রেটর রিমোট লোকেশন থেকে আপনার ব্রাউজারের সেটআপ পরিবর্তন করতে পারেন। এই ডিভাইসের অ্যাক্টিভিটি Chrome-এর বাইরে থেকেও ম্যানেজ করা যেতে পারে।</translation>
 <translation id="6648524591329069940">Serif হরফ</translation>
 <translation id="6651270836885078973">এটি ম্যানেজ করে:</translation>
@@ -2188,6 +2193,7 @@
 <translation id="9114524666733003316">কার্ড নিশ্চিত করা হচ্ছে...</translation>
 <translation id="9114581008513152754">কোনও কোম্পানি বা অন্য কোনও সংস্থা এই ব্রাউজার ম্যানেজ করে না। এই ডিভাইসের অ্যাক্টিভিটি Chrome-এর বাইরে থেকে ম্যানেজ করা যেতে পারে। <ph name="BEGIN_LINK" />আরও জানুন<ph name="END_LINK" /></translation>
 <translation id="9117930699067497412">তাজা</translation>
+<translation id="9118692854637641831">সার্চ করা আবার চালু করতে <ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ও তারপরে Enter প্রেস করুন এবং আপনার Chrome ইতিহাসে প্রাসঙ্গিক অ্যাক্টিভিটি দেখুন</translation>
 <translation id="9119042192571987207">আপলোড করা হয়েছে</translation>
 <translation id="9128016270925453879">নীতি লোড হয়েছে</translation>
 <translation id="9128870381267983090">নেটওয়ার্কে সংযোগ করুন</translation>
diff --git a/components/strings/components_strings_bs.xtb b/components/strings/components_strings_bs.xtb
index 0c357ab2..ac911e3 100644
--- a/components/strings/components_strings_bs.xtb
+++ b/components/strings/components_strings_bs.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Potvrda servera sadrži slab kriptografski ključ.</translation>
 <translation id="1696290444144917273">Pogledajte detalje virtuelne kartice</translation>
 <translation id="1697532407822776718">Sve je spremno!</translation>
+<translation id="1699570257714336246">Podaci nedostaju</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Ovaj server nije uspio dokazati da predstavlja domenu <ph name="DOMAIN" />; njegova potvrda sigurnosti je navodno izdata sutra. Uzrok tome može biti pogrešna konfiguracija ili napadač koji je prekinuo vašu vezu.}one{Ovaj server nije uspio dokazati da predstavlja domenu <ph name="DOMAIN" />; njegova potvrda sigurnosti je navodno izdata # dan u budućnosti. Uzrok tome može biti pogrešna konfiguracija ili napadač koji je prekinuo vašu vezu.}few{Ovaj server nije uspio dokazati da predstavlja domenu <ph name="DOMAIN" />; njegova potvrda sigurnosti je navodno izdata # dana u budućnosti. Uzrok tome može biti pogrešna konfiguracija ili napadač koji je prekinuo vašu vezu.}other{Ovaj server nije uspio dokazati da predstavlja domenu <ph name="DOMAIN" />; njegova potvrda sigurnosti je navodno izdata # dana u budućnosti. Uzrok tome može biti pogrešna konfiguracija ili napadač koji je prekinuo vašu vezu.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ca.xtb b/components/strings/components_strings_ca.xtb
index 4114ecc..586a0b9 100644
--- a/components/strings/components_strings_ca.xtb
+++ b/components/strings/components_strings_ca.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">El certificat de servidor conté una clau criptogràfica dèbil.</translation>
 <translation id="1696290444144917273">Mostra les dades de la targeta virtual</translation>
 <translation id="1697532407822776718">Ja estàs a punt!</translation>
+<translation id="1699570257714336246">Falta informació</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" /> perquè, suposadament, el seu certificat de seguretat té la data de demà. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.}other{Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" />; perquè, suposadament, el seu certificat de seguretat té una data que és d'aquí a # dies. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.}}</translation>
 <translation id="1710259589646384581">SO</translation>
diff --git a/components/strings/components_strings_cs.xtb b/components/strings/components_strings_cs.xtb
index 4d27896..b9bd6de 100644
--- a/components/strings/components_strings_cs.xtb
+++ b/components/strings/components_strings_cs.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Certifikát serveru obsahuje slabý kryptografický klíč.</translation>
 <translation id="1696290444144917273">Zobrazit podrobnosti o virtuální kartě</translation>
 <translation id="1697532407822776718">Vše je nastaveno!</translation>
+<translation id="1699570257714336246">Některé informace chybí</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Uvedené datum vystavení jeho bezpečnostního certifikátu je zítra. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.}few{Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Uvedené datum vystavení jeho bezpečnostního certifikátu je až za # dny. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.}many{Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Uvedené datum vystavení jeho bezpečnostního certifikátu je až za # dne. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.}other{Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Uvedené datum vystavení jeho bezpečnostního certifikátu je až za # dní. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.}}</translation>
 <translation id="1710259589646384581">Operační systém</translation>
diff --git a/components/strings/components_strings_da.xtb b/components/strings/components_strings_da.xtb
index c67d7d7..9bb2bae 100644
--- a/components/strings/components_strings_da.xtb
+++ b/components/strings/components_strings_da.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Servercertifikatet indeholder en svag kryptografisk nøgle.</translation>
 <translation id="1696290444144917273">Se virtuelle kortoplysninger</translation>
 <translation id="1697532407822776718">Fuldført</translation>
+<translation id="1699570257714336246">Der mangler oplysninger</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat tilsyneladende først gælder fra i morgen. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.}one{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat tilsyneladende først gælder fra om # dag. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.}other{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat tilsyneladende først gælder fra om # dage. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_de.xtb b/components/strings/components_strings_de.xtb
index 68ac049..cfb8f06 100644
--- a/components/strings/components_strings_de.xtb
+++ b/components/strings/components_strings_de.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Das Serverzertifikat weist einen schwachen kryptografischen Schlüssel auf.</translation>
 <translation id="1696290444144917273">Details der virtuellen Karte anzeigen</translation>
 <translation id="1697532407822776718">Fertig!</translation>
+<translation id="1699570257714336246">Fehlende Informationen</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst ab morgen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst in # Tagen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.}}</translation>
 <translation id="1710259589646384581">Betriebssystem</translation>
diff --git a/components/strings/components_strings_el.xtb b/components/strings/components_strings_el.xtb
index ad64d3d9..b0c84e5 100644
--- a/components/strings/components_strings_el.xtb
+++ b/components/strings/components_strings_el.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Το πιστοποιητικό διακομιστή περιέχει ένα αδύναμο κρυπτογραφικό κλειδί.</translation>
 <translation id="1696290444144917273">Προβολή λεπτομερειών εικονικής κάρτας</translation>
 <translation id="1697532407822776718">Είστε έτοιμοι!</translation>
+<translation id="1699570257714336246">Λείπουν πληροφορίες</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Αυτός ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Η ημερομηνία του πιστοποιητικού ασφαλείας του υποτίθεται ότι είναι αυριανή. Αυτό μπορεί να οφείλεται σε εσφαλμένη ρύθμιση ή σε κάποιον εισβολέα που παρεμβαίνει στη σύνδεσή σας.}other{Αυτός ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Η ημερομηνία του πιστοποιητικού ασφαλείας του υποτίθεται ότι είναι από # ημέρες μετά. Αυτό μπορεί να οφείλεται σε εσφαλμένη ρύθμιση ή σε κάποιον εισβολέα που παρεμβαίνει στη σύνδεσή σας.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_en-GB.xtb b/components/strings/components_strings_en-GB.xtb
index c7aaa22fb..cce012c8 100644
--- a/components/strings/components_strings_en-GB.xtb
+++ b/components/strings/components_strings_en-GB.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">The server certificate contains a weak cryptographic key.</translation>
 <translation id="1696290444144917273">View virtual card details</translation>
 <translation id="1697532407822776718">You're all set!</translation>
+<translation id="1699570257714336246">Information missing</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from tomorrow. This may be caused by a misconfiguration or an attacker intercepting your connection.}other{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_es-419.xtb b/components/strings/components_strings_es-419.xtb
index c1d8cd9..4ff4dbe 100644
--- a/components/strings/components_strings_es-419.xtb
+++ b/components/strings/components_strings_es-419.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">El certificado del servidor contiene una clave criptográfica no segura.</translation>
 <translation id="1696290444144917273">Ver detalles de la tarjeta virtual</translation>
 <translation id="1697532407822776718">¡Listo!</translation>
+<translation id="1699570257714336246">Falta información</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{El servidor no logró comprobar si el dominio es <ph name="DOMAIN" />; supuestamente, el certificado de seguridad entra en vigencia mañana. Es posible que esto se deba a una configuración incorrecta o a que un atacante haya interceptado la conexión.}other{El servidor no logró comprobar si el dominio es <ph name="DOMAIN" />; supuestamente, el certificado de seguridad entra en vigencia en # días. Es posible que esto se deba a una configuración incorrecta o a que un atacante haya interceptado la conexión.}}</translation>
 <translation id="1710259589646384581">SO</translation>
diff --git a/components/strings/components_strings_es.xtb b/components/strings/components_strings_es.xtb
index b2e2309..7f53dced 100644
--- a/components/strings/components_strings_es.xtb
+++ b/components/strings/components_strings_es.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">El certificado del servidor contiene una clave criptográfica no segura.</translation>
 <translation id="1696290444144917273">Ver los detalle de la tarjeta virtual</translation>
 <translation id="1697532407822776718">¡Listo!</translation>
+<translation id="1699570257714336246">Falta información</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad es válido a partir de mañana. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión.}other{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad es válido dentro de # días. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión.}}</translation>
 <translation id="1710259589646384581">Sistema operativo</translation>
diff --git a/components/strings/components_strings_et.xtb b/components/strings/components_strings_et.xtb
index 3eff36b..4ce22e5 100644
--- a/components/strings/components_strings_et.xtb
+++ b/components/strings/components_strings_et.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Serveri sertifikaat sisaldab nõrka krüptograafilist võtit.</translation>
 <translation id="1696290444144917273">Virtuaalkaardi üksikasjade kuvamine</translation>
 <translation id="1697532407822776718">Kõik on valmis!</translation>
+<translation id="1699570257714336246">Teave on puudu</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />, selle turvasertifikaat hakkab väidetavalt kehtima homme. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja.}other{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />, selle turvasertifikaat hakkab väidetavalt kehtima # päeva pärast. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja.}}</translation>
 <translation id="1710259589646384581">OS</translation>
@@ -917,7 +918,7 @@
 <translation id="4275830172053184480">Taaskäivitage seade</translation>
 <translation id="4277028893293644418">Lähtesta parool</translation>
 <translation id="428639260510061158">{NUM_CARDS,plural, =1{See kaart salvestati teie Google'i kontole}other{Need kaardid salvestati teie Google'i kontole}}</translation>
-<translation id="4287885627794386150">Prooviperioodiks sobiv, kuid see pole aktiivne</translation>
+<translation id="4287885627794386150">Prooviversiooniks sobiv, kuid pole aktiivne</translation>
 <translation id="4297502707443874121">Lehe <ph name="THUMBNAIL_PAGE" /> pisipilt</translation>
 <translation id="42981349822642051">Laienda</translation>
 <translation id="4300675098767811073">Mitu auku paremal</translation>
diff --git a/components/strings/components_strings_eu.xtb b/components/strings/components_strings_eu.xtb
index af0e697..a45fe038 100644
--- a/components/strings/components_strings_eu.xtb
+++ b/components/strings/components_strings_eu.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Zerbitzariaren ziurtagiriak okerreko gako kriptografikoa du.</translation>
 <translation id="1696290444144917273">Ikusi txartel birtualaren xehetasunak</translation>
 <translation id="1697532407822776718">Prest zaude!</translation>
+<translation id="1699570257714336246">Informazioa falta da</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Zerbitzariak ezin izan du frogatu <ph name="DOMAIN" /> dela; haren segurtasun-ziurtagiriak biharko data duela dirudi. Baliteke oker konfiguratuta dagoelako edo erasotzaile batek zure konexioa atzeman duelako izatea.}other{Zerbitzariak ezin izan du frogatu <ph name="DOMAIN" /> dela; haren segurtasun-ziurtagiriak gaurtik # egunerako data duela dirudi. Baliteke oker konfiguratuta dagoelako edo erasotzaile batek zure konexioa atzeman duelako izatea.}}</translation>
 <translation id="1710259589646384581">Sistema eragilea</translation>
diff --git a/components/strings/components_strings_fa.xtb b/components/strings/components_strings_fa.xtb
index 02f98ac..1654e8ec 100644
--- a/components/strings/components_strings_fa.xtb
+++ b/components/strings/components_strings_fa.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">گواهی‌نامه سرور دارای یک کلید رمزنگاری ضعیف است.</translation>
 <translation id="1696290444144917273">مشاهده جزئیات کارت مجازی</translation>
 <translation id="1697532407822776718">همه چیز مرتب است.</translation>
+<translation id="1699570257714336246">اطلاعات از دست می‌رود</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن ظاهراً فردا شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند.}one{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن ظاهراً # روز دیگر شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند.}other{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن ظاهراً # روز دیگر شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_fi.xtb b/components/strings/components_strings_fi.xtb
index 467aacd..fd52bda 100644
--- a/components/strings/components_strings_fi.xtb
+++ b/components/strings/components_strings_fi.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Palvelinvarmenne sisältää heikon salausavaimen.</translation>
 <translation id="1696290444144917273">Näytä virtuaalisen kortin tiedot</translation>
 <translation id="1697532407822776718">Kaikki on valmista.</translation>
+<translation id="1699570257714336246">Tietoja puuttuu</translation>
 <translation id="1703835215927279855">Kirje</translation>
 <translation id="1706954506755087368">{1,plural, =1{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on päivätty huomiselle. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.}other{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on päivätty # päivää tulevaisuuteen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.}}</translation>
 <translation id="1710259589646384581">Käyttöjärjestelmä</translation>
diff --git a/components/strings/components_strings_fil.xtb b/components/strings/components_strings_fil.xtb
index d93c0d4e..50bc158 100644
--- a/components/strings/components_strings_fil.xtb
+++ b/components/strings/components_strings_fil.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Naglalaman ang server certificate ng isang mahinang cryptographic key.</translation>
 <translation id="1696290444144917273">Tingnan ang mga detalye ng virtual na card.</translation>
 <translation id="1697532407822776718">Handa ka na!</translation>
+<translation id="1699570257714336246">May nawawalang impormasyon</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa susunod na araw ang certificate ng seguridad nito. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon.}one{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa # araw sa hinaharap ang certificate ng seguridad nito. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon.}other{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa # na araw sa hinaharap ang certificate ng seguridad nito. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_fr-CA.xtb b/components/strings/components_strings_fr-CA.xtb
index 32c79d2..5876d07a 100644
--- a/components/strings/components_strings_fr-CA.xtb
+++ b/components/strings/components_strings_fr-CA.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Le certificat du serveur contient une clé de chiffrement faible.</translation>
 <translation id="1696290444144917273">Afficher les renseignements de la carte virtuelle</translation>
 <translation id="1697532407822776718">Vous êtes prêt!</translation>
+<translation id="1699570257714336246">Renseignements manquants</translation>
 <translation id="1703835215927279855">Lettre</translation>
 <translation id="1706954506755087368">{1,plural, =1{Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car la date d'émission de son certificat de sécurité semble dater de demain. Cela peut être dû à une mauvaise configuration ou à l'interception de votre connexion par un pirate informatique.}one{Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car la date d'émission de son certificat de sécurité est ultérieure de # jour à la date du jour. Cela peut être dû à une mauvaise configuration ou à l'interception de votre connexion par un pirate informatique.}other{Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car la date d'émission de son certificat de sécurité est ultérieure de # jours à la date du jour. Cela peut être dû à une mauvaise configuration ou à l'interception de votre connexion par un pirate informatique.}}</translation>
 <translation id="1710259589646384581">Systèmes d'exploitation</translation>
diff --git a/components/strings/components_strings_fr.xtb b/components/strings/components_strings_fr.xtb
index 28969c73..3a5e2d7 100644
--- a/components/strings/components_strings_fr.xtb
+++ b/components/strings/components_strings_fr.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Le certificat du serveur contient une clé de chiffrement faible.</translation>
 <translation id="1696290444144917273">Afficher les informations relatives à la carte virtuelle</translation>
 <translation id="1697532407822776718">Vous êtes prêt !</translation>
+<translation id="1699570257714336246">Informations manquantes</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'émission de son certificat de sécurité est fixée à demain. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.}one{Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'émission de son certificat de sécurité est ultérieure de # jour à la date du jour. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.}other{Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'émission de son certificat de sécurité est ultérieure de # jours à la date du jour. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.}}</translation>
 <translation id="1710259589646384581">Système d'exploitation</translation>
diff --git a/components/strings/components_strings_gl.xtb b/components/strings/components_strings_gl.xtb
index e3076a6..ae60eea 100644
--- a/components/strings/components_strings_gl.xtb
+++ b/components/strings/components_strings_gl.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">O certificado do servidor contén unha clave criptográfica non segura.</translation>
 <translation id="1696290444144917273">Ver detalles da tarxeta virtual</translation>
 <translation id="1697532407822776718">Listo!</translation>
+<translation id="1699570257714336246">Falta información</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque o seu certificado de seguranza supostamente é válido a partir de mañá. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.}other{Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque o seu certificado de seguranza supostamente é válido dentro de # días. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.}}</translation>
 <translation id="1710259589646384581">Sistema operativo</translation>
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb
index 56f2d70a..1e68b028 100644
--- a/components/strings/components_strings_gu.xtb
+++ b/components/strings/components_strings_gu.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">સર્વર પ્રમાણપત્ર એક નબળી ક્રિપ્ટોગ્રાફિક કી ધરાવે છે.</translation>
 <translation id="1696290444144917273">વર્ચ્યુઅલ કાર્ડની વિગતો જુઓ</translation>
 <translation id="1697532407822776718">તમારું બધું સેટ છે!</translation>
+<translation id="1699570257714336246">માહિતી ખૂટે છે</translation>
 <translation id="1703835215927279855">અક્ષર</translation>
 <translation id="1706954506755087368">{1,plural, =1{આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર આવતીકાલથી માનવામાં આવે છે તે પ્રમાણે છે. આ કોઇ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઇ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.}one{આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર માનવામાં આવે છે તે પ્રમાણે ભવિષ્યમાં # દિવસથી છે. આ કોઇ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઇ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.}other{આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર માનવામાં આવે છે તે પ્રમાણે ભવિષ્યમાં # દિવસથી છે. આ કોઇ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઇ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_hi.xtb b/components/strings/components_strings_hi.xtb
index a0261ac4..9d0a21c 100644
--- a/components/strings/components_strings_hi.xtb
+++ b/components/strings/components_strings_hi.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">सर्वर प्रमाणपत्र में कमज़ोर क्रिप्टोग्राफ़िक कुंजी है.</translation>
 <translation id="1696290444144917273">वर्चुअल कार्ड की जानकारी देखें</translation>
 <translation id="1697532407822776718">आप बिल्कुल तैयार हैं!</translation>
+<translation id="1699570257714336246">जानकारी मौजूद नहीं है</translation>
 <translation id="1703835215927279855">लेटर</translation>
 <translation id="1706954506755087368">{1,plural, =1{यह सर्वर प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र कल से माना जाएगा. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन को बाधित करने के कारण हो सकता है.}one{यह सर्वर प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र # दिन बाद से माना जाएगा. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन को बाधित करने के कारण हो सकता है.}other{यह सर्वर प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र # दिन बाद से माना जाएगा. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन को बाधित करने के कारण हो सकता है.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_hr.xtb b/components/strings/components_strings_hr.xtb
index 5879efa9..3b7fb913 100644
--- a/components/strings/components_strings_hr.xtb
+++ b/components/strings/components_strings_hr.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Certifikat poslužitelja sadrži slab kriptografski ključ!</translation>
 <translation id="1696290444144917273">Pregledajte pojedinosti virtualne kartice</translation>
 <translation id="1697532407822776718">Potpuno ste spremni!</translation>
+<translation id="1699570257714336246">Nedostaju podaci</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan sutra. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}one{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dan u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}few{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dana u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}other{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dana u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_hu.xtb b/components/strings/components_strings_hu.xtb
index 70d569fd..05dd515 100644
--- a/components/strings/components_strings_hu.xtb
+++ b/components/strings/components_strings_hu.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">A szervertanúsítvány gyenge titkosítási kulcsot tartalmaz.</translation>
 <translation id="1696290444144917273">Virtuális kártya adatainak megtekintése</translation>
 <translation id="1697532407822776718">Máris elkészült!</translation>
+<translation id="1699570257714336246">Hiányzó információ</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa elméletileg holnaptól érvényes. Ennek oka lehet konfigurációs hiba, de az is lehet, hogy egy támadó eltérítette az Ön kapcsolódását.}other{A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa elméletileg # nap múlva lép érvénybe. Ennek oka lehet konfigurációs hiba, de az is lehet, hogy egy támadó eltérítette az Ön kapcsolódását.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_hy.xtb b/components/strings/components_strings_hy.xtb
index 9dda317b..9dc0e687 100644
--- a/components/strings/components_strings_hy.xtb
+++ b/components/strings/components_strings_hy.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Սերվերի վկայագիրը թույլ գաղտնագրման բանալի ունի:</translation>
 <translation id="1696290444144917273">Դիտել վիրտուալ քարտի տվյալները</translation>
 <translation id="1697532407822776718">Տեղակայումը բարեհաջող ավարտված է:</translation>
+<translation id="1699570257714336246">Տեղեկություններ չկան</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Այս սերվերը չկարողացավ ապացուցել, որ ինքը <ph name="DOMAIN" /> տիրույթն է: Դրա անվտանգության հավաստագիրը ենթադրաբար վաղվանից վավեր կդառնա: Պատճառը կարող է լինել սխալ կազմաձևումը կամ հաքերային հարձակումը ձեր կապուղու զավթմամբ և գաղտնալսմամբ։}one{սերվերը չկարողացավ ապացուցել, որ ինքը <ph name="DOMAIN" /> տիրույթն է: Դրա անվտանգության հավաստագիրը ենթադրաբար վավեր կդառնա # օր հետո: Պատճառը կարող է լինել սխալ կազմաձևումը կամ հաքերային հարձակումը ձեր կապուղու զավթմամբ և գաղտնալսմամբ։}other{Այս սերվերը չկարողացավ ապացուցել, որ ինքը <ph name="DOMAIN" /> տիրույթն է: Դրա անվտանգության հավաստագիրը ենթադրաբար վավեր կդառնա # օր հետո: Պատճառը կարող է լինել սխալ կազմաձևումը կամ հաքերային հարձակումը ձեր կապուղու զավթմամբ և գաղտնալսմամբ։}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_id.xtb b/components/strings/components_strings_id.xtb
index b1d62d1..5186e49491 100644
--- a/components/strings/components_strings_id.xtb
+++ b/components/strings/components_strings_id.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Sertifikat server berisi kunci kriptografis yang lemah.</translation>
 <translation id="1696290444144917273">Lihat detail kartu virtual</translation>
 <translation id="1697532407822776718">Anda sudah siap!</translation>
+<translation id="1699570257714336246">Informasi tidak ada</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya sepertinya dari esok hari. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas koneksi internet Anda.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya sepertinya dari # hari mendatang. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas koneksi internet Anda.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_is.xtb b/components/strings/components_strings_is.xtb
index a79b823..20913dee 100644
--- a/components/strings/components_strings_is.xtb
+++ b/components/strings/components_strings_is.xtb
@@ -220,6 +220,7 @@
 <translation id="168841957122794586">Vottorð netþjónsins inniheldur ótraustan dulmálslykil.</translation>
 <translation id="1696290444144917273">Skoða frekari upplýsingar um sýndarkort</translation>
 <translation id="1697532407822776718">Nú er allt tilbúið!</translation>
+<translation id="1699570257714336246">Upplýsingar vantar</translation>
 <translation id="1703835215927279855">Bréf</translation>
 <translation id="1706954506755087368">{1,plural, =1{Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; öryggisvottorð hans er að sögn gefið út á morgun. Þetta kann að orsakast af rangri stillingu eða tölvuþrjóti sem hefur komist inn í tenginguna.}one{Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; öryggisvottorð hans er að sögn gefið út eftir # dag. Þetta kann að orsakast af rangri stillingu eða tölvuþrjóti sem hefur komist inn í tenginguna.}other{Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; öryggisvottorð hans er að sögn gefið út eftir # daga. Þetta kann að orsakast af rangri stillingu eða tölvuþrjóti sem hefur komist inn í tenginguna.}}</translation>
 <translation id="1710259589646384581">Stýrikerfi</translation>
diff --git a/components/strings/components_strings_it.xtb b/components/strings/components_strings_it.xtb
index c9cf5d7..55e41897 100644
--- a/components/strings/components_strings_it.xtb
+++ b/components/strings/components_strings_it.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Il certificato del server contiene una chiave crittografica debole.</translation>
 <translation id="1696290444144917273">Visualizza i dettagli della carta virtuale</translation>
 <translation id="1697532407822776718">Ecco fatto!</translation>
+<translation id="1699570257714336246">Mancano informazioni</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo da domani. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo tra # giorni. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}}</translation>
 <translation id="1710259589646384581">Sistema operativo</translation>
diff --git a/components/strings/components_strings_iw.xtb b/components/strings/components_strings_iw.xtb
index 4da5a2d..48e7f823 100644
--- a/components/strings/components_strings_iw.xtb
+++ b/components/strings/components_strings_iw.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">אישור השרת מכיל מפתח הצפנה חלש.</translation>
 <translation id="1696290444144917273">הצגת הפרטים של הכרטיס הווירטואלי</translation>
 <translation id="1697532407822776718">הכול מוכן!</translation>
+<translation id="1699570257714336246">חסר מידע</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />; אישור האבטחה שלו אמור להיכנס לתוקף רק מחר. ייתכן שהסיבה לכך היא הגדרה שגויה או שתוקף מיירט את החיבור שלך.}two{השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />; אישור האבטחה שלו אמור להיכנס לתוקף רק בעוד יומיים. ייתכן שהסיבה לכך היא הגדרה שגויה או שתוקף מיירט את החיבור שלך.}many{השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />; אישור האבטחה שלו אמור להיכנס לתוקף רק בעוד # ימים. ייתכן שהסיבה לכך היא הגדרה שגויה או שתוקף מיירט את החיבור שלך.}other{השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />; אישור האבטחה שלו אמור להיכנס לתוקף רק בעוד # ימים. ייתכן שהסיבה לכך היא הגדרה שגויה או שתוקף מיירט את החיבור שלך.}}</translation>
 <translation id="1710259589646384581">מערכת הפעלה</translation>
diff --git a/components/strings/components_strings_ja.xtb b/components/strings/components_strings_ja.xtb
index 1820b26..4a4b18b9 100644
--- a/components/strings/components_strings_ja.xtb
+++ b/components/strings/components_strings_ja.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">サーバー証明書に脆弱な暗号鍵が含まれています。</translation>
 <translation id="1696290444144917273">仮想カードの詳細を表示します</translation>
 <translation id="1697532407822776718">設定が完了しました。</translation>
+<translation id="1699570257714336246">情報が不足しています</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。セキュリティ証明書はおそらく明日以降に利用できるようになります。原因として、設定が不適切であるか、悪意のあるユーザーが接続を妨害していることが考えられます。}other{このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。セキュリティ証明書はおそらく # 日後から利用できるようになります。原因として、設定が不適切であるか、悪意のあるユーザーが接続を妨害していることが考えられます。}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ka.xtb b/components/strings/components_strings_ka.xtb
index f0c527b..410cd3c 100644
--- a/components/strings/components_strings_ka.xtb
+++ b/components/strings/components_strings_ka.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">სერვერის სერთიფიკატი შეიცავს სუსტ კრიპტოგრაფიულ გასაღებს.</translation>
 <translation id="1696290444144917273">ვირტუალური ბარათის დეტალების ნახვა</translation>
 <translation id="1697532407822776718">ყველაფერი დაყენებულია!</translation>
+<translation id="1699570257714336246">აკლია ინფორმაცია</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{ეს სერვერი ვერ ამტკიცებს, რომ ის არის <ph name="DOMAIN" />; მისი უსაფრთხოების სერტიფიკატი, სავარაუდოდ, ხვალინდელია. ამის მიზეზი შეიძლება იყოს არასწორი კონფიგურაცია ან შესაძლოა, თქვენი კავშირი თავდამსხმელს ჰქონდეს ხელში ჩაგდებული.}other{ეს სერვერი ვერ ამტკიცებს, რომ ის არის <ph name="DOMAIN" />; მისი უსაფრთხოების სერტიფიკატის ვადა, სავარაუდოდ, # დღის შემდეგ იწყება. ამის მიზეზი შეიძლება იყოს არასწორი კონფიგურაცია ან შესაძლოა, თქვენი კავშირი თავდამსხმელს ჰქონდეს ხელში ჩაგდებული.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_kk.xtb b/components/strings/components_strings_kk.xtb
index 484ef527..1d608565 100644
--- a/components/strings/components_strings_kk.xtb
+++ b/components/strings/components_strings_kk.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сервер сертификаты сенімсіз криптографиялық кілтті қамтиды.</translation>
 <translation id="1696290444144917273">Виртуалды карта мәліметтерін көру</translation>
 <translation id="1697532407822776718">Барлығын орнаттыңыз!</translation>
+<translation id="1699570257714336246">Ақпарат жоқ</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Бұл сервер өзінің <ph name="DOMAIN" /> екендігін дәлелдей алмады; оның қауіпсіздік сертификаты ертеңнен басталатын сияқты. Бұл дұрыс конфигурацияланбағаннан немесе зиянды бағдарламаның байланысқа кедергі келтіруінен болуы мүмкін.}other{Бұл сервер өзінің <ph name="DOMAIN" /> екендігін дәлелдей алмады; оның қауіпсіздік сертификаты # күн өткеннен кейін басталатын сияқты. Бұл дұрыс конфигурацияланбағаннан немесе зиянды бағдарламаның байланысқа кедергі келтіруінен болуы мүмкін.}}</translation>
 <translation id="1710259589646384581">ОЖ</translation>
diff --git a/components/strings/components_strings_km.xtb b/components/strings/components_strings_km.xtb
index 6f1a4c2..6ecc1c4 100644
--- a/components/strings/components_strings_km.xtb
+++ b/components/strings/components_strings_km.xtb
@@ -220,6 +220,7 @@
 <translation id="168841957122794586">វិញ្ញាបនប័ត្រម៉ាស៊ីនមេផ្ទុកសោគ្រីបខ្សោយ។</translation>
 <translation id="1696290444144917273">មើលព័ត៌មានលម្អិត​អំពីកាតនិម្មិត</translation>
 <translation id="1697532407822776718">អ្នកត្រូវបានកំណត់រួចអស់ហើយ!</translation>
+<translation id="1699570257714336246">បាត់ព័ត៌មាន</translation>
 <translation id="1703835215927279855">សំបុត្រ</translation>
 <translation id="1706954506755087368">{1,plural, =1{ម៉ាស៊ីនមេនេះមិនអាចបង្ហាញថាវាជា <ph name="DOMAIN" /> ទេ។ វិញ្ញាបនបត្រសុវត្ថិភាពរបស់វាត្រូវបានសន្មតថាមានសុពលភាពចាប់ពីថ្ងៃស្អែកទៅ។ វាអាចបណ្តាលមកពីការកំណត់រចនាសម្ព័ន្ធខុស ឬអ្នកវាយប្រហារកំពុងរារាំងការតភ្ជាប់របស់អ្នក។}other{ម៉ាស៊ីនមេនេះមិនអាចបង្ហាញថាវាជា <ph name="DOMAIN" /> ទេ។ វិញ្ញាបនបត្រសុវត្ថិភាពរបស់វាត្រូវបានសន្មតថាមានសុពលភាពក្នុងរយៈពេល # ថ្ងៃបន្ទាប់។ វាអាចបណ្តាលមកពីការកំណត់រចនាសម្ព័ន្ធខុស ឬអ្នកវាយប្រហារកំពុងរារាំងការតភ្ជាប់របស់អ្នក។}}</translation>
 <translation id="1710259589646384581">ប្រព័ន្ធប្រតិបត្តិការ</translation>
diff --git a/components/strings/components_strings_kn.xtb b/components/strings/components_strings_kn.xtb
index c3f2fc4..0eaddc24 100644
--- a/components/strings/components_strings_kn.xtb
+++ b/components/strings/components_strings_kn.xtb
@@ -218,6 +218,7 @@
 <translation id="168841957122794586">ಸರ್ವರ್ ಪ್ರಮಾಣಪತ್ರವು ದುರ್ಬಲ ಕ್ರಿಪ್ಟೋಗ್ರಾಫಿಕ್ ಕೀಯನ್ನು ಹೊಂದಿದೆ.</translation>
 <translation id="1696290444144917273">ವರ್ಚುವಲ್ ಕಾರ್ಡ್ ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಿ</translation>
 <translation id="1697532407822776718">ನೀವು ಎಲ್ಲ ರೀತಿಯಲ್ಲಿಯೂ ಸಿದ್ಧರಾಗಿರುವಿರಿ!</translation>
+<translation id="1699570257714336246">ಮಾಹಿತಿ ಕಾಣೆಯಾಗಿದೆ</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ; ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರ ಬಹುಶಃ ನಾಳೆಯಿಂದ ಕಾರ್ಯನಿರ್ವಹಿಸಬಹುದು. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.}one{ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರ ಬಹುಶಃ ಭವಿಷ್ಯದಲ್ಲಿ # ದಿನಗಳಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸಬಹುದು. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.}other{ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರ ಬಹುಶಃ ಭವಿಷ್ಯದಲ್ಲಿ # ದಿನಗಳಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸಬಹುದು. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ko.xtb b/components/strings/components_strings_ko.xtb
index c529c17..cd04fe5 100644
--- a/components/strings/components_strings_ko.xtb
+++ b/components/strings/components_strings_ko.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">서버 인증서에 안전성이 낮은 암호화 키가 포함되어 있습니다.</translation>
 <translation id="1696290444144917273">가상 카드 세부정보 보기</translation>
 <translation id="1697532407822776718">설정 완료</translation>
+<translation id="1699570257714336246">정보 누락</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{서버의 보안 인증서가 내일 발효될 예정이며 이에 따라 <ph name="DOMAIN" />임을 입증할 수 없습니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.}other{서버의 보안 인증서가 #일 후 발효될 예정이며 이에 따라 <ph name="DOMAIN" />임을 입증할 수 없습니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ky.xtb b/components/strings/components_strings_ky.xtb
index 48a6f51..f9c684a 100644
--- a/components/strings/components_strings_ky.xtb
+++ b/components/strings/components_strings_ky.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сервердин тастыктамасында чабал криптографиялык ачкыч камтылган.</translation>
 <translation id="1696290444144917273">Виртуалдык картанын чоо-жайын көрүү</translation>
 <translation id="1697532407822776718">Баары даяр!</translation>
+<translation id="1699570257714336246">Маалымат жетишсиз</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Бул сервер <ph name="DOMAIN" /> экенин далилдей алган жок. Анын коопсуздук тастыктамасы эртең күчүнө кирет. Мындай көйгөй сервердин туура эмес конфигурацияланышы менен шартталышы мүмкүн же кимдир-бирөө ортодон дайын-даректериңизди кармап калганга аракет кылып жатат.}other{Бул сервер <ph name="DOMAIN" /> экенин далилдей алган жок. Анын коопсуздук тастыктамасы # күндөн кийин күчүнө кирет. Мындай көйгөй сервердин туура эмес конфигурацияланышы менен шартталышы мүмкүн же кимдир-бирөө ортодон дайын-даректериңизди кармап калганга аракет кылып жатат.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_lo.xtb b/components/strings/components_strings_lo.xtb
index bdc667b..99e595e8 100644
--- a/components/strings/components_strings_lo.xtb
+++ b/components/strings/components_strings_lo.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">ໃບຢັ້ງຢືນເຊີບເວີມີລະຫັດ cryptographic ທີ່ອ່ອນ.</translation>
 <translation id="1696290444144917273">ເບິ່ງລາຍລະອຽດບັດສະເໝືອນ</translation>
 <translation id="1697532407822776718">ທ່ານຕັ້ງຮຽບຮ້ອຍໝົດແລ້ວ!</translation>
+<translation id="1699570257714336246">ຂໍ້ມູນຫາຍໄປ</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{ເຊີບ​ເວີ​ນີ້​ບໍ່​ສາ​ມາດ​ພິ​ສູດ​ໄດ້​ວ່າ​ມັນ​ແມ່ນ <ph name="DOMAIN" />;ໃບ​ຢັ້ງ​ຢືນ​ຄວາມ​ປອດ​ໄພ​ຂອງ​ທ່ານ​ແມ່ນ​ຄາດ​ວ່າ​ຈະຕັ້ງ​ແຕ່​ມື້​ອື່ນ​ໄປ. ອັນນີ້ອາດຈະເຮັດໃຫ້ເກີດມີການກຳນົດຄ່າຄ່າຜິດ ຫຼື ຜູ້ໂຈມຕີອາດຈະດັກສະກັດການເຊື່ອມຕໍ່ຂອງທ່ານ.}other{ເຊີບ​ເວີ​ນີ້​ບໍ່​ສາ​ມາດ​ພິ​ສູດ​ໄດ້​ວ່າ​ມັນ​ແມ່ນ <ph name="DOMAIN" />; ໃບ​ຢັ້ງ​ຢືນ​ຄວາມ​ປອດ​ໄພ​ຂອງ​ທ່ານ​ແມ່ນ​ຄາດ​ວ່າ​ຈະ​ຕັ້ງ​ແຕ່ # ວັນ​ໃນ​ອະ​ນາ​ຄົດ. ອັນນີ້ອາດຈະເຮັດໃຫ້ເກີດມີການກຳນົດຄ່າຄ່າຜິດ ຫຼື ຜູ້ໂຈມຕີອາດຈະດັກສະກັດການເຊື່ອມຕໍ່ຂອງທ່ານ.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_lt.xtb b/components/strings/components_strings_lt.xtb
index 797e37e..08a7569 100644
--- a/components/strings/components_strings_lt.xtb
+++ b/components/strings/components_strings_lt.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Serverio sertifikate yra nesudėtingas kriptografinis raktas.</translation>
 <translation id="1696290444144917273">Peržiūrėkite išsamią virtualios kortelės informaciją</translation>
 <translation id="1697532407822776718">Viskas nustatyta!</translation>
+<translation id="1699570257714336246">Trūksta informacijos</translation>
 <translation id="1703835215927279855">Laiškas</translation>
 <translation id="1706954506755087368">{1,plural, =1{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios nuo rytojaus. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}one{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienos. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}few{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}many{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienos. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}other{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_lv.xtb b/components/strings/components_strings_lv.xtb
index bf1c474..834c2951 100644
--- a/components/strings/components_strings_lv.xtb
+++ b/components/strings/components_strings_lv.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Servera sertifikāts ietver vāju kriptogrāfisko atslēgu.</translation>
 <translation id="1696290444144917273">Skatīt virtuālās kartītes informāciju</translation>
 <translation id="1697532407822776718">Gatavs!</translation>
+<translation id="1699570257714336246">Trūkst informācijas</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Šis serveris nevarēja pierādīt, ka ir <ph name="DOMAIN" />; šķiet, ka tā drošības sertifikāts sāks darboties rīt. Šī problēma var rasties nepareizas konfigurācijas dēļ vai tādēļ, ka kāds uzbrucējs ir pārtvēris jūsu savienojumu.}zero{Šis serveris nevarēja pierādīt, ka ir <ph name="DOMAIN" />; šķiet, ka tā drošības sertifikāts sāks darboties pēc # dienām. Šī problēma var rasties nepareizas konfigurācijas dēļ vai tādēļ, ka kāds uzbrucējs ir pārtvēris jūsu savienojumu.}one{Šis serveris nevarēja pierādīt, ka ir <ph name="DOMAIN" />; šķiet, ka tā drošības sertifikāts sāks darboties pēc # dienas. Šī problēma var rasties nepareizas konfigurācijas dēļ vai tādēļ, ka kāds uzbrucējs ir pārtvēris jūsu savienojumu.}other{Šis serveris nevarēja pierādīt, ka ir <ph name="DOMAIN" />; šķiet, ka tā drošības sertifikāts sāks darboties pēc # dienām. Šī problēma var rasties nepareizas konfigurācijas dēļ vai tādēļ, ka kāds uzbrucējs ir pārtvēris jūsu savienojumu.}}</translation>
 <translation id="1710259589646384581">Operētājsistēma</translation>
diff --git a/components/strings/components_strings_mk.xtb b/components/strings/components_strings_mk.xtb
index 98739764..cc63ffc0 100644
--- a/components/strings/components_strings_mk.xtb
+++ b/components/strings/components_strings_mk.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сертификатот на серверот содржи слаб криптографски клуч.</translation>
 <translation id="1696290444144917273">Прегледајте ги деталите од виртуелната картичка</translation>
 <translation id="1697532407822776718">Подготвени сте.</translation>
+<translation id="1699570257714336246">Недостасува информација</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедносен сертификат наводно е утрешен. Тоа можеби се должи на погрешна конфигурација или на напаѓач што ја пресретнува вашата врска.}one{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедносен сертификат наводно е после # ден во иднината. Тоа можеби се должи на погрешна конфигурација или на напаѓач што ја пресретнува вашата врска.}other{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедносен сертификат наводно е после # дена во иднината. Тоа можеби се должи на погрешна конфигурација или на напаѓач што ја пресретнува вашата врска.}}</translation>
 <translation id="1710259589646384581">ОС</translation>
diff --git a/components/strings/components_strings_ml.xtb b/components/strings/components_strings_ml.xtb
index 37ab0c3..4b3cfbc 100644
--- a/components/strings/components_strings_ml.xtb
+++ b/components/strings/components_strings_ml.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">സെർവർ സർട്ടിഫിക്കറ്റിൽ ഒരു ദുർബലമായ ഗൂഢഭാഷ കീ ഉൾപ്പെടുന്നു.</translation>
 <translation id="1696290444144917273">വെർച്വൽ കാർഡ് വിശദാംശങ്ങൾ കാണുക</translation>
 <translation id="1697532407822776718">എല്ലാം സജ്ജമായിക്കഴിഞ്ഞു!</translation>
+<translation id="1699570257714336246">വിവരങ്ങൾ സമ്പൂർണ്ണമല്ല</translation>
 <translation id="1703835215927279855">ലെറ്റർ</translation>
 <translation id="1706954506755087368">{1,plural, =1{ഈ സെർവറിന് ഇത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; അതിന്റെ സുരക്ഷാ സർട്ടിഫിക്കറ്റ് ഇന്നലെ മുതൽ സാധുവല്ല. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു ആക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.}other{ഈ സെർവറിന് ഇത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; അതിന്റെ സുരക്ഷാ സർട്ടിഫിക്കറ്റ് # ദിവസം മുതൽ സാധുവായിരിക്കില്ല. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു ആക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_mn.xtb b/components/strings/components_strings_mn.xtb
index 6161672..f3b49b0 100644
--- a/components/strings/components_strings_mn.xtb
+++ b/components/strings/components_strings_mn.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Серверийн гэрчилгээний криптограф түлхүүр нь аюулгүй байдлын хувьд сул байна.</translation>
 <translation id="1696290444144917273">Виртуал картын дэлгэрэнгүйг үзэх</translation>
 <translation id="1697532407822776718">Тохируулга дууссан</translation>
+<translation id="1699570257714336246">Мэдээлэл дутуу байна</translation>
 <translation id="1703835215927279855">Захидал</translation>
 <translation id="1706954506755087368">{1,plural, =1{Энэ сервер нь <ph name="DOMAIN" /> гэдгээ баталгаажуулж чадсангүй; серверийн аюулгүй байдлын сертификат маргаашнаас эхэлнэ. Энэ нь буруу тохируулснаас, эсвэл халдагч этгээд таны холболтод саад учруулснаас болсон байж болзошгүй.}other{Энэ сервер нь <ph name="DOMAIN" /> гэдгээ баталгаажуулж чадсангүй; серверийн аюулгүй байдлын сертификат # хоногоос хүчинтэй болно. Энэ нь буруу тохируулснаас, эсвэл халдагч этгээд таны холболтод саад учруулснаас болсон байж болзошгүй.}}</translation>
 <translation id="1710259589646384581">Үйлдлийн систем</translation>
diff --git a/components/strings/components_strings_mr.xtb b/components/strings/components_strings_mr.xtb
index 0da98d68..e02504f1 100644
--- a/components/strings/components_strings_mr.xtb
+++ b/components/strings/components_strings_mr.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">सर्व्हर सर्टिफिकेटमध्ये एक कमकुवत क्रिप्टोग्राफिक की आहे.</translation>
 <translation id="1696290444144917273">व्हर्च्युअल कार्डचे तपशील पहा</translation>
 <translation id="1697532407822776718">तुम्ही पूर्णपणे तयार आहात!</translation>
+<translation id="1699570257714336246">माहिती नाही आहे</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षा सर्टिफिकेट उद्यापासून मानले जाईल. हे कदाचित एका चुकीच्या कॉंफिगरेशनमुळे किंवा हल्लेखोराने तुमचे कनेक्शन इंटरसेप्ट केल्यामुळे झाले असू शकते.}other{हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षा सर्टिफिकेट पुढील # दिवसांपासून मानले जाईल. हे कदाचित एका चुकीच्या कॉंफिगरेशनमुळे किंवा हल्लेखोराने तुमचे कनेक्शन इंटरसेप्ट केल्यामुळे झाले असू शकते.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ms.xtb b/components/strings/components_strings_ms.xtb
index cd60195f..652874d 100644
--- a/components/strings/components_strings_ms.xtb
+++ b/components/strings/components_strings_ms.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Sijil pelayan mengandungi kunci kriptografi yang lemah.</translation>
 <translation id="1696290444144917273">Lihat butiran kad maya</translation>
 <translation id="1697532407822776718">Anda telah bersedia!</translation>
+<translation id="1699570257714336246">Tiada maklumat</translation>
 <translation id="1703835215927279855">Surat</translation>
 <translation id="1706954506755087368">{1,plural, =1{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />;sijil keselamatannya sepatutnya bermula esok. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda.}other{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya sepatutnya bermula # hari lagi. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_my.xtb b/components/strings/components_strings_my.xtb
index 71092e41..6f9037ee 100644
--- a/components/strings/components_strings_my.xtb
+++ b/components/strings/components_strings_my.xtb
@@ -220,6 +220,7 @@
 <translation id="168841957122794586">ဆာဗာ အသိမှတ်ပြုလက်မှတ်တွင် အားနည်းသည့် ကုဒ်ရေးခြင်းကီး ပါဝင်နေသည်!</translation>
 <translation id="1696290444144917273">ပကတိအသွင်ကတ် အသေးစိတ်ကို ကြည့်ရန်</translation>
 <translation id="1697532407822776718">သင်သည် အားလုံးကို သတ်မှတ်ပြီးသွားပြီ!</translation>
+<translation id="1699570257714336246">အချက်အလက်များ လိုအပ်နေသည်</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{ဤဆာဗာက ၎င်းသည် <ph name="DOMAIN" /> ဖြစ်ကြောင်း သက်သေထူမပြနိုင်ပါ၊ ၎င်း၏ လုံခြုံရေး လက်မှတ်မှာ နက်ဖြန်တွင် စတင်မည်။ စီဖွဲ့မှုလွဲမှားနေ၍ သို့မဟုတ် သင့်ချိတ်ဆက်မှုကို ကြားဖြတ်ယူခဲ့သည့် တိုက်ခိုက်သူကြောင့် ထိုသို့ ဖြစ်လာနိုင်ခဲ့ပါသည်။}other{ဤဆာဗာက ၎င်းမှာ <ph name="DOMAIN" /> ဖြစ်ကြောင်း သက်သေထူမပြနိုင်ပါ၊ ၎င်း၏ လုံခြုံရေး လက်မှတ်မှာ အနာဂတ် # ရက်တွင် စတင်ပါမည်။ စီဖွဲ့မှုလွဲမှားနေ၍ သို့မဟုတ် သင့်ချိတ်ဆက်မှုကို ကြားဖြတ်ယူခဲ့သည့် တိုက်ခိုက်သူကြောင့် ထိုသို့ ဖြစ်လာနိုင်ခဲ့ပါသည်။}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ne.xtb b/components/strings/components_strings_ne.xtb
index 06754bf..9d6bc1f 100644
--- a/components/strings/components_strings_ne.xtb
+++ b/components/strings/components_strings_ne.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">सर्भर प्रमाणपत्रले कमजोर क्रिप्टोग्राफिक कुञ्जी समावेश गर्छ।</translation>
 <translation id="1696290444144917273">भर्चुअल कार्डका विवरण हेर्नुहोस्</translation>
 <translation id="1697532407822776718">तपाईंहरू सबैले सेट हुनभयो!</translation>
+<translation id="1699570257714336246">जानकारी छुटेको छ</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{ यो सर्भरले यो <ph name="DOMAIN" /> हो भनेर प्रमाणित गर्न सकेन; यसको सुरक्षा प्रमाणपत्रलाई भोलिबाट मानिन्छ। गलत कन्फिगुरेसन वा कुनै आक्रमणकारीले तपाईँको जडानमा अवरोध गरिरहेको कारणले यसो भएको हुन सक्छ।}other{ यो सर्भरले यो <ph name="DOMAIN" /> हो भनेर प्रमाणित गर्न सकेन; यसको सुरक्षा प्रमाणपत्रलाई # दिनबाट शुरू हुन्छ भनेर मानिन्छ। गलत कन्फिगुरेसन वा कुनै आक्रमणकारीले तपाईँको जडानमा अवरोध गरिरहेको कारणले यसो भएको हुन सक्छ।}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_nl.xtb b/components/strings/components_strings_nl.xtb
index 2398ac2e..19ed2ed 100644
--- a/components/strings/components_strings_nl.xtb
+++ b/components/strings/components_strings_nl.xtb
@@ -217,6 +217,7 @@
 <translation id="168841957122794586">Het servercertificaat bevat een zwakke cryptografische sleutel.</translation>
 <translation id="1696290444144917273">Gegevens van virtuele kaart bekijken</translation>
 <translation id="1697532407822776718">Je bent nu klaar!</translation>
+<translation id="1699570257714336246">Ontbrekende informatie</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is zogenaamd van morgen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.}other{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is zogenaamd van # dagen in de toekomst. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.}}</translation>
 <translation id="1710259589646384581">Besturingssysteem</translation>
diff --git a/components/strings/components_strings_no.xtb b/components/strings/components_strings_no.xtb
index c6ebab2..637adde 100644
--- a/components/strings/components_strings_no.xtb
+++ b/components/strings/components_strings_no.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Tjenersertifikatet inneholder en svak kryptografisk nøkkel.</translation>
 <translation id="1696290444144917273">Se virtuelle kortopplysninger</translation>
 <translation id="1697532407822776718">Da er alt klart!</translation>
+<translation id="1699570257714336246">Informasjon mangler</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ser ut til å være fra i morgen. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen mellom deg og nettstedet.}other{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ser ut til å være fra # dager frem i tid. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen mellom deg og nettstedet.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_or.xtb b/components/strings/components_strings_or.xtb
index c146ce3..171a19f 100644
--- a/components/strings/components_strings_or.xtb
+++ b/components/strings/components_strings_or.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">ସର୍ଭର୍ ସାର୍ଟିଫିକେଟ୍‍‍ରେ ଗୋଟିଏ ଦୁର୍ବଳ କ୍ରିପ୍ଟୋଗ୍ରାଫିକ୍ କୀ ଅଛି।</translation>
 <translation id="1696290444144917273">ଭର୍ଚୁଆଲ୍ କାର୍ଡ ବିବରଣୀ ଦେଖନ୍ତୁ</translation>
 <translation id="1697532407822776718">ଆପଣ ପୂରା ପ୍ରସ୍ତୁତ ଅଛନ୍ତି!</translation>
+<translation id="1699570257714336246">ସୂଚନା ଅନୁପଲବ୍ଧ ଅଛି</translation>
 <translation id="1703835215927279855">ଲେଟର୍</translation>
 <translation id="1706954506755087368">{1,plural, =1{ଏହି ସର୍ଭର୍‌ ପ୍ରମାଣ କରିପାରିଲା ନାହିଁ ଯେ ଏହା <ph name="DOMAIN" /> ଅଟେ; ଏହାର ସୁରକ୍ଷା ସର୍ଟିଫିକେଟ୍‍ ଆସନ୍ତାକାଲିଠାରୁ ସ୍ୱୀକାର କରାଯିବ। ଏହା ହୁଏତ ଏକ ଭୁଲ୍ କନଫିଗ୍‍‍ରେସନ୍ କିମ୍ବା ଜଣେ ଆକ୍ରମଣକାରୀ ଆପଣଙ୍କର ସଂଯୋଗକୁ ପ୍ରତିରୋଧ କରୁଥିବା କାରଣରୁ ହୋଇପାରେ।}other{ଏହି ସର୍ଭର୍‌ ପ୍ରମାଣ କରିପାରିଲା ନାହିଁ ଯେ ଏହା <ph name="DOMAIN" /> ଅଟେ; ଏହାର ସୁରକ୍ଷା ସର୍ଟିଫିକେଟ୍‍ ଭବିଷ୍ୟତରେ # ଦିନଠାରୁ ସ୍ୱୀକାର କରାଯିବ। ଏହା ହୁଏତ ଏକ ଭୁଲ୍ କନଫିଗ୍‍‍ରେସନ୍ କିମ୍ବା ଜଣେ ଆକ୍ରମଣକାରୀ ଆପଣଙ୍କର ସଂଯୋଗକୁ ପ୍ରତିରୋଧ କରୁଥିବା କାରଣରୁ ହୋଇପାରେ।}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_pa.xtb b/components/strings/components_strings_pa.xtb
index 7981f6f..a2ec3db0 100644
--- a/components/strings/components_strings_pa.xtb
+++ b/components/strings/components_strings_pa.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">ਸਰਵਰ ਸਰਟੀਫਿਕੇਟ ਵਿੱਚ ਇੱਕ ਕਮਜ਼ੋਰ ਕ੍ਰਾਈਪਟੋਗ੍ਰਾਫਿਕ ਕੁੰਜੀ ਹੈ।</translation>
 <translation id="1696290444144917273">ਆਭਾਸੀ ਕਾਰਡ ਸੰਬੰਧੀ ਵੇਰਵੇ ਦੇਖੋ</translation>
 <translation id="1697532407822776718">ਤੁਸੀਂ ਸਾਰਾ ਸੈਟ ਕਰ ਲਿਆ ਹੈ!</translation>
+<translation id="1699570257714336246">ਜਾਣਕਾਰੀ ਅਧੂਰੀ ਹੈ</translation>
 <translation id="1703835215927279855">ਚਿੱਠੀ</translation>
 <translation id="1706954506755087368">{1,plural, =1{ਇਹ ਸਰਵਰ ਇਹ ਸਿੱਧ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" />ਹੈ; ਇਸਦਾ ਸੁਰੱਖਿਆ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਭਵਿੱਖ ਵਿੱਚ ਕੱਲ੍ਹ ਤੋਂ ਅਨੁਮਾਨਿਤ ਤੌਰ ਤੇ ਹੈ। ਇਸ ਦਾ ਕਾਰਨ ਕੋਈ ਗਲਤ ਸੰਰੂਪਣ ਜਾਂ ਕਿਸੇ ਹਮਲਾਵਰ ਵੱਲੋਂ ਤੁਹਾਡੇ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕਣਾ ਹੋ ਸਕਦਾ ਹੈ।}one{ਇਹ ਸਰਵਰ ਇਹ ਸਿੱਧ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸੁਰੱਖਿਆ ਸਰਟੀਫਿਕੇਟ ਭਵਿੱਖ ਵਿੱਚ # ਦਿਨਾਂ ਤੋਂ ਅਨੁਮਾਨਿਤ ਤੌਰ ਤੇ ਹੈ। ਇਸ ਦਾ ਕਾਰਨ ਕੋਈ ਗਲਤ ਸੰਰੂਪਣ ਜਾਂ ਕਿਸੇ ਹਮਲਾਵਰ ਵੱਲੋਂ ਤੁਹਾਡੇ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕਣਾ ਹੋ ਸਕਦਾ ਹੈ।}other{ਇਹ ਸਰਵਰ ਇਹ ਸਿੱਧ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸੁਰੱਖਿਆ ਸਰਟੀਫਿਕੇਟ ਭਵਿੱਖ ਵਿੱਚ # ਦਿਨਾਂ ਤੋਂ ਅਨੁਮਾਨਿਤ ਤੌਰ ਤੇ ਹੈ। ਇਸ ਦਾ ਕਾਰਨ ਕੋਈ ਗਲਤ ਸੰਰੂਪਣ ਜਾਂ ਕਿਸੇ ਹਮਲਾਵਰ ਵੱਲੋਂ ਤੁਹਾਡੇ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕਣਾ ਹੋ ਸਕਦਾ ਹੈ।}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_pl.xtb b/components/strings/components_strings_pl.xtb
index 1d5c6cff..2e917041 100644
--- a/components/strings/components_strings_pl.xtb
+++ b/components/strings/components_strings_pl.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Certyfikat serwera ma słaby klucz kryptograficzny.</translation>
 <translation id="1696290444144917273">Zobacz dane karty wirtualnej</translation>
 <translation id="1697532407822776718">Wszystko gotowe.</translation>
+<translation id="1699570257714336246">Brak informacji</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa przypuszczalnie zacznie obowiązywać od jutra. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia.}few{Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa przypuszczalnie zacznie obowiązywać za # dni. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia.}many{Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa przypuszczalnie zacznie obowiązywać za # dni. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia.}other{Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa przypuszczalnie zacznie obowiązywać za # dnia. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia.}}</translation>
 <translation id="1710259589646384581">System operacyjny</translation>
diff --git a/components/strings/components_strings_pt-BR.xtb b/components/strings/components_strings_pt-BR.xtb
index 3666b641..aa43e6b 100644
--- a/components/strings/components_strings_pt-BR.xtb
+++ b/components/strings/components_strings_pt-BR.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">O certificado do servidor contém uma chave de criptografia fraca.</translation>
 <translation id="1696290444144917273">Ver detalhes do cartão virtual</translation>
 <translation id="1697532407822776718">Pronto.</translation>
+<translation id="1699570257714336246">Faltam algumas informações</translation>
 <translation id="1703835215927279855">Carta</translation>
 <translation id="1706954506755087368">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele está com a data de amanhã. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.}one{Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele está com uma data de # dias depois de hoje. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.}other{Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele está com uma data de # dias depois de hoje. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.}}</translation>
 <translation id="1710259589646384581">SO</translation>
diff --git a/components/strings/components_strings_pt-PT.xtb b/components/strings/components_strings_pt-PT.xtb
index 2c518cd..281bdf3 100644
--- a/components/strings/components_strings_pt-PT.xtb
+++ b/components/strings/components_strings_pt-PT.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">O certificado do servidor contém uma chave criptográfica fraca.</translation>
 <translation id="1696290444144917273">Veja detalhes do cartão virtual</translation>
 <translation id="1697532407822776718">O processo está concluído!</translation>
+<translation id="1699570257714336246">Informações em falta</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o seu certificado de segurança é supostamente de amanhã. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.}other{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; a data do seu certificado de segurança é supostamente daqui a # dias. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.}}</translation>
 <translation id="1710259589646384581">SO</translation>
diff --git a/components/strings/components_strings_ro.xtb b/components/strings/components_strings_ro.xtb
index fb4f993..f5cf8f08 100644
--- a/components/strings/components_strings_ro.xtb
+++ b/components/strings/components_strings_ro.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Certificatul de server conține o cheie criptografică slabă.</translation>
 <translation id="1696290444144917273">Vezi detaliile cardului virtual</translation>
 <translation id="1697532407822776718">Ești gata!</translation>
+<translation id="1699570257714336246">Informații lipsă</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este mâine. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator.}few{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este în viitor, peste # zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator.}other{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este în viitor, peste # de zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator.}}</translation>
 <translation id="1710259589646384581">Sistem de operare</translation>
diff --git a/components/strings/components_strings_ru.xtb b/components/strings/components_strings_ru.xtb
index 443c625..e178ad5 100644
--- a/components/strings/components_strings_ru.xtb
+++ b/components/strings/components_strings_ru.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сертификат сервера содержит ненадежный криптографический ключ.</translation>
 <translation id="1696290444144917273">Показать реквизиты виртуальной карты</translation>
 <translation id="1697532407822776718">Готово!</translation>
+<translation id="1699570257714336246">Данные отсутствуют</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности вступит в силу завтра. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.}one{Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности вступит в силу через # день. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.}few{Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности вступит в силу через # дня. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.}many{Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности вступит в силу через # дней. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.}other{Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности вступит в силу через # дня. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.}}</translation>
 <translation id="1710259589646384581">ОС</translation>
diff --git a/components/strings/components_strings_si.xtb b/components/strings/components_strings_si.xtb
index 228f378..f119b91 100644
--- a/components/strings/components_strings_si.xtb
+++ b/components/strings/components_strings_si.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">සේවාදායක සහතිකයේ දුර්වල ගුප්තලේඛන යතුරක් අඩංගුය!</translation>
 <translation id="1696290444144917273">අතථ්‍ය කාඩ්පත් විස්තර බලන්න</translation>
 <translation id="1697532407822776718">ඔබ මුළුමනින් සුදානම්ය!</translation>
+<translation id="1699570257714336246">තොරතුරු මඟ හැරී ඇත</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{මෙම සේවාදායකයට එය <ph name="DOMAIN" /> බව සනාථ කළ නොහැකි විය; එහි ආරක්ෂණ සහතිකය හෙට සිට විය හැකිය. මෙය වැරදි වින්‍යාස කිරීමක් හෝ ප්‍රහාරකයකු ඔබගේ සබැඳුමට බාධා කිරීමක් නිසා විය හැකිය.}one{මෙම සේවාදායකයට එය <ph name="DOMAIN" /> බව සනාථ කළ නොහැකි විය; එහි ආරක්ෂණ සහතිකය අනාගතයේදී දින #ක් සිට විය හැකිය. මෙය වැරදි වින්‍යාස කිරීමක් හෝ ප්‍රහාරකයකු ඔබගේ සබැඳුමට බාධා කිරීමක් නිසා විය හැකිය.}other{මෙම සේවාදායකයට එය <ph name="DOMAIN" />බව සනාථ කළ නොහැකි විය; එහි ආරක්ෂණ සහතිකය අනාගතයේදී දින #ක් සිට විය හැකිය. මෙය වැරදි වින්‍යාස කිරීමක් හෝ ප්‍රහාරකයකු ඔබගේ සබැඳුමට බාධා කිරීමක් නිසා විය හැකිය.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_sk.xtb b/components/strings/components_strings_sk.xtb
index 4f14ee4..7fa14b3c 100644
--- a/components/strings/components_strings_sk.xtb
+++ b/components/strings/components_strings_sk.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Certifikát servera obsahuje slabý kryptografický kľúč.</translation>
 <translation id="1696290444144917273">Zobraziť podrobnosti virtuálnej karty</translation>
 <translation id="1697532407822776718">Všetko je nastavené!</translation>
+<translation id="1699570257714336246">Chýbajú informácie</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Tomuto serveru sa nepodarilo dokázať, že ide o doménu <ph name="DOMAIN" />; jej certifikát by mal začať platiť od zajtra. Môže to byť následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útočníkom.}few{Tomuto serveru sa nepodarilo dokázať, že ide o doménu <ph name="DOMAIN" />; jej certifikát by mal začať platiť o # dni. Môže to byť následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útočníkom.}many{Tomuto serveru sa nepodarilo dokázať, že ide o doménu <ph name="DOMAIN" />; jej certifikát by mal začať platiť o # dňa. Môže to byť následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útočníkom.}other{Tomuto serveru sa nepodarilo dokázať, že ide o doménu <ph name="DOMAIN" />; jej certifikát by mal začať platiť o # dní. Môže to byť následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útočníkom.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_sl.xtb b/components/strings/components_strings_sl.xtb
index 2d0701e..c14d7a1 100644
--- a/components/strings/components_strings_sl.xtb
+++ b/components/strings/components_strings_sl.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Potrdilo strežnika vsebuje šibek šifrirni ključ.</translation>
 <translation id="1696290444144917273">Ogled podrobnosti navidezne kartice</translation>
 <translation id="1697532407822776718">Pripravljeni ste.</translation>
+<translation id="1699570257714336246">Manjkajo podatki</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo jutrišnji datum. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.}one{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dan od danes. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.}two{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dneva od danes. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.}few{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dni od danes. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.}other{Strežniku ni uspelo dokazati, dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dni od danes. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.}}</translation>
 <translation id="1710259589646384581">Operacijski sistem</translation>
diff --git a/components/strings/components_strings_sq.xtb b/components/strings/components_strings_sq.xtb
index 13dd2a0..55e746fc 100644
--- a/components/strings/components_strings_sq.xtb
+++ b/components/strings/components_strings_sq.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Certifikata e serverit përmban një çelës të dobët kriptografik.</translation>
 <translation id="1696290444144917273">Shiko detajet e kartës virtuale</translation>
 <translation id="1697532407822776718">Je gati!</translation>
+<translation id="1699570257714336246">Mungon informacion</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Ky server nuk mund të vërtetonte se është <ph name="DOMAIN" />; certifikata e tij e sigurisë supozohet se është nga dita e nesërme. Kjo mund të jetë shkaktuar nga një konfigurim i gabuar ose nga ndërhyrja e një sulmuesi në lidhjen tënde.}other{ky server nuk mund të vërtetonte se është <ph name="DOMAIN" />; certifikata e tij e sigurisë supozohet se është nga # ditë në të ardhmen. Kjo mund të jetë shkaktuar nga një konfigurim i gabuar ose nga ndërhyrja e një sulmuesi në lidhjen tënde.}}</translation>
 <translation id="1710259589646384581">Sistemi operativ</translation>
diff --git a/components/strings/components_strings_sr-Latn.xtb b/components/strings/components_strings_sr-Latn.xtb
index e59da9af..ae77bd5a 100644
--- a/components/strings/components_strings_sr-Latn.xtb
+++ b/components/strings/components_strings_sr-Latn.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Sertifikat servera sadrži slab kriptografski ključ.</translation>
 <translation id="1696290444144917273">Pogledajte podatke o virtuelnoj kartici</translation>
 <translation id="1697532407822776718">Spremni ste!</translation>
+<translation id="1699570257714336246">Nedostaju informacije</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; datum njegovog bezbednosnog sertifikata je navodno sutrašnji. Uzrok tome je možda pogrešna konfiguracija ili napadač koji je prekinuo vezu.}one{Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat je navodno datiran u budućnosti (za # dan). Uzrok tome je možda pogrešna konfiguracija ili napadač koji je prekinuo vezu.}few{Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat je navodno datiran u budućnosti (za # dana). Uzrok tome je možda pogrešna konfiguracija ili napadač koji je prekinuo vezu.}other{Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat je navodno datiran u budućnosti (za # dana). Uzrok tome je možda pogrešna konfiguracija ili napadač koji je prekinuo vezu.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_sr.xtb b/components/strings/components_strings_sr.xtb
index a1a1d90..ae7e8d3 100644
--- a/components/strings/components_strings_sr.xtb
+++ b/components/strings/components_strings_sr.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сертификат сервера садржи слаб криптографски кључ.</translation>
 <translation id="1696290444144917273">Погледајте податке о виртуелној картици</translation>
 <translation id="1697532407822776718">Спремни сте!</translation>
+<translation id="1699570257714336246">Недостају информације</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Овај сервер не може да докаже да је <ph name="DOMAIN" />; датум његовог безбедносног сертификата је наводно сутрашњи. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.}one{Овај сервер не може да докаже да је <ph name="DOMAIN" />; његов безбедносни сертификат је наводно датиран у будућности (за # дан). Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.}few{Овај сервер не може да докаже да је <ph name="DOMAIN" />; његов безбедносни сертификат је наводно датиран у будућности (за # дана). Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.}other{Овај сервер не може да докаже да је <ph name="DOMAIN" />; његов безбедносни сертификат је наводно датиран у будућности (за # дана). Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.}}</translation>
 <translation id="1710259589646384581">ОС</translation>
diff --git a/components/strings/components_strings_sv.xtb b/components/strings/components_strings_sv.xtb
index 4b6b4e83..7a247a4 100644
--- a/components/strings/components_strings_sv.xtb
+++ b/components/strings/components_strings_sv.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Servercertifikatet innehåller en svag kryptografisk nyckel.</translation>
 <translation id="1696290444144917273">Visa kortuppgifter</translation>
 <translation id="1697532407822776718">Färdigt!</translation>
+<translation id="1699570257714336246">Uppgifter saknas</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat uppges börja gälla i morgon. Det kan bero på att servern är felkonfigurerad eller att anslutningen har blivit kapad.}other{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat uppges börja gälla om # dagar. Det kan bero på att servern är felkonfigurerad eller att anslutningen har blivit kapad.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_sw.xtb b/components/strings/components_strings_sw.xtb
index a73af1ab..d4ee64a 100644
--- a/components/strings/components_strings_sw.xtb
+++ b/components/strings/components_strings_sw.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Cheti cha seva kina kitufe dhaifu cha kifichua msimbo.</translation>
 <translation id="1696290444144917273">Angalia maelezo ya kadi pepe</translation>
 <translation id="1697532407822776718">Mko tayari nyote!</translation>
+<translation id="1699570257714336246">Maelezo hayajakamilika</translation>
 <translation id="1703835215927279855">Barua</translation>
 <translation id="1706954506755087368">{1,plural, =1{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kitakwisha muda kuanzia kesho. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.}other{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kitakwisha muda kuanzia siku # zijazo. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_ta.xtb b/components/strings/components_strings_ta.xtb
index 097af10..58564f5 100644
--- a/components/strings/components_strings_ta.xtb
+++ b/components/strings/components_strings_ta.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">சேவையக சான்றிதழில் வலுவற்ற குறியீட்டாக்க விசை இருக்கிறது.</translation>
 <translation id="1696290444144917273">விர்ச்சுவல் கார்டு விவரங்களைக் காட்டும்</translation>
 <translation id="1697532407822776718">எல்லாவற்றையும் அமைத்துவிட்டீர்கள்!</translation>
+<translation id="1699570257714336246">தகவல் முழுமையாக இல்லை</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{இந்தச் சேவையகம் தான் <ph name="DOMAIN" /> என்பதை நிரூபிக்க முடியவில்லை; இதன் பாதுகாப்புச் சான்றிதழ் நாளை முதலே செல்லுபடியாகும். இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.}other{இந்தச் சேவையகம் தான் <ph name="DOMAIN" /> என்பதை நிரூபிக்க முடியவில்லை; இதன் பாதுகாப்புச் சான்றிதழ் எதிர்காலத்தில் # நாட்களில் ஏற்றுக்கொள்ளப்படும். இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index 357c39d..fab0577 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -221,6 +221,7 @@
 <translation id="168841957122794586">సర్వర్ ప్రమాణపత్రం బలహీన క్రిప్టోగ్రాఫిక్ కీని కలిగి ఉంది.</translation>
 <translation id="1696290444144917273">వర్చువల్ కార్డ్ వివరాలను చూడండి</translation>
 <translation id="1697532407822776718">మీరు సిద్ధంగా ఉన్నారు!</translation>
+<translation id="1699570257714336246">సమాచారం సరిగ్గా లేదు</translation>
 <translation id="1703835215927279855">లెటర్</translation>
 <translation id="1706954506755087368">{1,plural, =1{ఈ సర్వర్ ఇది <ph name="DOMAIN" /> అని నిరూపించలేకపోయింది; దీని భద్రతా ప్రమాణపత్రం రేపటిది కావచ్చు. తప్పుగా కాన్ఫిగర్ చేసినందున లేదా దాడిచేసేవారు మీ కనెక్షన్‌కు అంతరాయం కలిగించినందున ఇలా జరిగి ఉండవచ్చు.}other{ఈ సర్వర్ ఇది <ph name="DOMAIN" /> అని నిరూపించలేకపోయింది; దీని భద్రతా ప్రమాణపత్రం భవిష్యత్తులో # రోజుల తదుపరిది కావచ్చు. తప్పుగా కాన్ఫిగర్ చేసినందున లేదా దాడిచేసేవారు మీ కనెక్షన్‌కు అంతరాయం కలిగించినందున ఇలా జరిగి ఉండవచ్చు.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_th.xtb b/components/strings/components_strings_th.xtb
index a43ed20..e2d0ecf0 100644
--- a/components/strings/components_strings_th.xtb
+++ b/components/strings/components_strings_th.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">ใบรับรองของเซิร์ฟเวอร์มีคีย์การเข้ารหัสที่ไม่รัดกุม</translation>
 <translation id="1696290444144917273">ดูรายละเอียดบัตรเสมือน</translation>
 <translation id="1697532407822776718">คุณพร้อมแล้ว!</translation>
+<translation id="1699570257714336246">ข้อมูลไม่ครบ</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยควรจะเริ่มใช้งานได้ตั้งแต่วันพรุ่งนี้ โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ}other{เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยควรจะเริ่มใช้งานได้ในอีก # วันข้างหน้า โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ}}</translation>
 <translation id="1710259589646384581">ระบบปฏิบัติการ</translation>
diff --git a/components/strings/components_strings_tr.xtb b/components/strings/components_strings_tr.xtb
index 81a3a4d..fd6fab4 100644
--- a/components/strings/components_strings_tr.xtb
+++ b/components/strings/components_strings_tr.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Sunucu sertifikasında zayıf bir şifreleme anahtarı var.</translation>
 <translation id="1696290444144917273">Sanal kart ayrıntılarını görüntüle</translation>
 <translation id="1697532407822776718">Artık hazırsınız!</translation>
+<translation id="1699570257714336246">Bilgi eksik</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Bu sunucu, <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikasının alınma tarihinin yarın olduğu iddia ediliyor. Bu durum, bir yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir.}other{Bu sunucu, <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikasının alınma tarihinin # gün sonra olduğu iddia ediliyor. Bu durum, bir yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_uk.xtb b/components/strings/components_strings_uk.xtb
index 54d6a5b3..1c3001a 100644
--- a/components/strings/components_strings_uk.xtb
+++ b/components/strings/components_strings_uk.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Сертифікат сервера містить слабкий криптографічний ключ.</translation>
 <translation id="1696290444144917273">Переглянути дані віртуальної картки</translation>
 <translation id="1697532407822776718">Готово!</translation>
+<translation id="1699570257714336246">Немає інформації</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Не вдалося підтвердити, що це сервер <ph name="DOMAIN" />. Його сертифікат безпеки почне діяти завтра. Можливо, сервер налаштовано неправильно або хтось намагається перехопити ваші дані.}one{Не вдалося підтвердити, що це сервер <ph name="DOMAIN" />. Його сертифікат безпеки почне діяти через # день. Можливо, сервер налаштовано неправильно або хтось намагається перехопити ваші дані.}few{Не вдалося підтвердити, що це сервер <ph name="DOMAIN" />. Його сертифікат безпеки почне діяти через # дні. Можливо, сервер налаштовано неправильно або хтось намагається перехопити ваші дані.}many{Не вдалося підтвердити, що це сервер <ph name="DOMAIN" />. Його сертифікат безпеки почне діяти через # днів. Можливо, сервер налаштовано неправильно або хтось намагається перехопити ваші дані.}other{Не вдалося підтвердити, що це сервер <ph name="DOMAIN" />. Його сертифікат безпеки почне діяти через # дня. Можливо, сервер налаштовано неправильно або хтось намагається перехопити ваші дані.}}</translation>
 <translation id="1710259589646384581">ОС</translation>
diff --git a/components/strings/components_strings_ur.xtb b/components/strings/components_strings_ur.xtb
index 3908999..a0daa02 100644
--- a/components/strings/components_strings_ur.xtb
+++ b/components/strings/components_strings_ur.xtb
@@ -220,6 +220,7 @@
 <translation id="168841957122794586">سرور سرٹیفکیٹ میں ایک ہفتے کی کرپٹوگرافک کلید شامل ہے۔</translation>
 <translation id="1696290444144917273">ورچوئل کارڈ کی تفصیلات دیکھیں</translation>
 <translation id="1697532407822776718">آپ بالکل ٹھیک ہیں!</translation>
+<translation id="1699570257714336246">معلومات موجود نہیں ہے</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{یہ سرور ثابت نہیں کر سکا کہ یہ <ph name="DOMAIN" /> ہے؛ اس کے سیکیورٹی سرٹیفکیٹ کی میعاد ممکنہ طور پر کل سے ہے۔ یہ غلط کنفیگریشن یا آپ کے کنکشن کو قطع کرنے والے کسی حملہ آور کی وجہ سے ہو سکتا ہے۔}other{یہ سرور ثابت نہیں کر سکا کہ یہ <ph name="DOMAIN" /> ہے؛ اس کے سیکیورٹی سرٹیفکیٹ کی میعاد ممکنہ طور پر مستقبل میں  # دن بعد سے ہے۔ یہ غلط کنفیگریشن یا آپ کے کنکشن کو قطع کرنے والے کسی حملہ آور کی وجہ سے ہو سکتا ہے۔}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_uz.xtb b/components/strings/components_strings_uz.xtb
index b196b47..74f8697b 100644
--- a/components/strings/components_strings_uz.xtb
+++ b/components/strings/components_strings_uz.xtb
@@ -218,6 +218,7 @@
 <translation id="168841957122794586">Server sertifikati ishonchsiz kriptografik kalitga ega.</translation>
 <translation id="1696290444144917273">Virtual karta tafsilotlarini ochish</translation>
 <translation id="1697532407822776718">Tayyor!</translation>
+<translation id="1699570257714336246">Axborot butunlay kiritilmadi</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Server bu domenni <ph name="DOMAIN" /> ekanligini tasdiqlay olmaydi. Uning xavfsizlik sertifikati ertadan boshlab shubhali hisoblanadi. Balki, server noto‘g‘ri sozlangan yoki kimdir ma’lumotlaringizni o‘g‘irlashga urinayotgan bo‘lishi mumkin.}other{Server bu domenni <ph name="DOMAIN" /> ekanligini tasdiqlay olmaydi. Uning xavfsizlik sertifikati # kundan keyin kuchga kiradi. Balki, server noto‘g‘ri sozlangan yoki kimdir ma’lumotlaringizni o‘g‘irlashga urinayotgan bo‘lishi mumkin.}}</translation>
 <translation id="1710259589646384581">OT</translation>
diff --git a/components/strings/components_strings_vi.xtb b/components/strings/components_strings_vi.xtb
index 37743e5..a554560 100644
--- a/components/strings/components_strings_vi.xtb
+++ b/components/strings/components_strings_vi.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Chứng chỉ máy chủ chứa khóa mật mã yếu.</translation>
 <translation id="1696290444144917273">Xem thông tin chi tiết về thẻ ảo</translation>
 <translation id="1697532407822776718">Bạn đã hoàn tất!</translation>
+<translation id="1699570257714336246">Thiếu thông tin</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này được đề từ ngày mai. Điều này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.}other{Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này được đề # ngày trong tương lai. Điều này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.}}</translation>
 <translation id="1710259589646384581">OS</translation>
diff --git a/components/strings/components_strings_zh-CN.xtb b/components/strings/components_strings_zh-CN.xtb
index dc4d37c..6f94fb2 100644
--- a/components/strings/components_strings_zh-CN.xtb
+++ b/components/strings/components_strings_zh-CN.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">服务器证书包含弱加密密钥。</translation>
 <translation id="1696290444144917273">查看虚拟卡详细信息</translation>
 <translation id="1697532407822776718">搞定了!</translation>
+<translation id="1699570257714336246">缺少信息</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{此服务器无法证明它是 <ph name="DOMAIN" />;其安全证书明天才会生效。出现此问题的原因可能是配置有误,或有攻击者拦截了您的连接。}other{此服务器无法证明它是 <ph name="DOMAIN" />;其安全证书 # 天后才会生效。出现此问题的原因可能是配置有误,或有攻击者拦截了您的连接。}}</translation>
 <translation id="1710259589646384581">操作系统</translation>
diff --git a/components/strings/components_strings_zh-HK.xtb b/components/strings/components_strings_zh-HK.xtb
index d43e17f..b3ae8aa4 100644
--- a/components/strings/components_strings_zh-HK.xtb
+++ b/components/strings/components_strings_zh-HK.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">伺服器憑證含有防護力薄弱的加密編譯金鑰。</translation>
 <translation id="1696290444144917273">查看虛擬付款卡資料</translation>
 <translation id="1697532407822776718">大功告成!</translation>
+<translation id="1699570257714336246">缺少資料</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{伺服器無法證明屬於 <ph name="DOMAIN" /> 網域;其安全性憑證預期於明天生效。這可能是由於設定錯誤,或有攻擊者攔截您的連線。}other{伺服器無法證明屬於 <ph name="DOMAIN" /> 網域;其安全性憑證預期於 # 天後生效。這可能是由於設定錯誤,或有攻擊者攔截您的連線。}}</translation>
 <translation id="1710259589646384581">作業系統</translation>
diff --git a/components/strings/components_strings_zh-TW.xtb b/components/strings/components_strings_zh-TW.xtb
index 04c1c05..70b747a 100644
--- a/components/strings/components_strings_zh-TW.xtb
+++ b/components/strings/components_strings_zh-TW.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">伺服器憑證含有防護力薄弱的加密編譯金鑰。</translation>
 <translation id="1696290444144917273">查看虛擬卡片資料</translation>
 <translation id="1697532407822776718">大功告成!</translation>
+<translation id="1699570257714336246">缺少資訊</translation>
 <translation id="1703835215927279855">Letter</translation>
 <translation id="1706954506755087368">{1,plural, =1{這個伺服器無法證明所在網域是 <ph name="DOMAIN" />;伺服器的安全性憑證預定明天才生效。這可能是因為設定錯誤,或是有攻擊者攔截您的連線。}other{這個伺服器無法證明所在網域是 <ph name="DOMAIN" />;伺服器的安全性憑證預定 # 天後才生效。這可能是因為設定錯誤,或是有攻擊者攔截您的連線。}}</translation>
 <translation id="1710259589646384581">作業系統</translation>
diff --git a/components/strings/components_strings_zu.xtb b/components/strings/components_strings_zu.xtb
index 91fc5a6..34cd2aaa 100644
--- a/components/strings/components_strings_zu.xtb
+++ b/components/strings/components_strings_zu.xtb
@@ -219,6 +219,7 @@
 <translation id="168841957122794586">Isitifiketi seseva siqukethe ukhiye we-cryptographic obuthaka.</translation>
 <translation id="1696290444144917273">Buka imininingwane yekhadi elibonakalayo</translation>
 <translation id="1697532407822776718">Senisethiwe nonke!</translation>
+<translation id="1699570257714336246">Ulwazi alukho</translation>
 <translation id="1703835215927279855">Incwadi</translation>
 <translation id="1706954506755087368">{1,plural, =1{Le seva ayikwazanga ukufakazela ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikela singahle sivele kusukela kusasa. Lokhu kungabangelwa ukungalungisi kahle noma umhlaseli ohlangabeza ukuxhumeka kwakho.}one{Le seva ayikwazanga ukufakazela ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikela singahle sivele kusuka ezinsukwini ezingu-# ngokuzayo. Lokhu kungabangelwa ukungalungisi kahle noma umhlaseli ohlangabeza ukuxhumeka kwakho.}other{Le seva ayikwazanga ukufakazela ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikela singahle sivele kusuka ezinsukwini ezingu-# ngokuzayo. Lokhu kungabangelwa ukungalungisi kahle noma umhlaseli ohlangabeza ukuxhumeka kwakho.}}</translation>
 <translation id="1710259589646384581">I-OS</translation>
diff --git a/components/subresource_redirect/common/subresource_redirect_result.h b/components/subresource_redirect/common/subresource_redirect_result.h
index dae817b..0454aeb3c 100644
--- a/components/subresource_redirect/common/subresource_redirect_result.h
+++ b/components/subresource_redirect/common/subresource_redirect_result.h
@@ -65,11 +65,8 @@
   // got disabled.
   kIneligibleFirstKDisableSubresourceRedirect = 12,
 
-  // Because the subresource redirection was disabled, where only metrics are
-  // recorded and the actual subresource redirection does not happen.
-  kIneligibleCompressionDisabled = 13,
-
-  kMaxValue = SubresourceRedirectResult::kIneligibleCompressionDisabled
+  kMaxValue =
+      SubresourceRedirectResult::kIneligibleFirstKDisableSubresourceRedirect
 };
 
 }  // namespace subresource_redirect
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 5a958b59..6b18b6fd 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -1472,6 +1472,10 @@
       accounts_in_cookie_jar_info.signed_in_accounts, base::NullCallback());
 }
 
+void ProfileSyncService::OnAccountsCookieDeletedByUserAction() {
+  sync_client_->GetTrustedVaultClient()->RemoveAllStoredKeys();
+}
+
 void ProfileSyncService::OnAccountsInCookieUpdatedWithCallback(
     const std::vector<gaia::ListedAccount>& signed_in_accounts,
     base::OnceClosure callback) {
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index c760a382..adbca0d 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -184,6 +184,7 @@
   void OnAccountsInCookieUpdated(
       const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
       const GoogleServiceAuthError& error) override;
+  void OnAccountsCookieDeletedByUserAction() override;
 
   // Similar to above but with a callback that will be invoked on completion.
   void OnAccountsInCookieUpdatedWithCallback(
diff --git a/components/sync/driver/sync_service_crypto.cc b/components/sync/driver/sync_service_crypto.cc
index 49c2f250..8985797a 100644
--- a/components/sync/driver/sync_service_crypto.cc
+++ b/components/sync/driver/sync_service_crypto.cc
@@ -55,6 +55,11 @@
     NOTREACHED();
   }
 
+  void RemoveAllStoredKeys() override {
+    // Never invoked by SyncServiceCrypto.
+    NOTREACHED();
+  }
+
   void MarkKeysAsStale(const CoreAccountInfo& account_info,
                        base::OnceCallback<void(bool)> cb) override {
     std::move(cb).Run(false);
diff --git a/components/sync/driver/sync_service_crypto_unittest.cc b/components/sync/driver/sync_service_crypto_unittest.cc
index f853f34..8cc20ce9 100644
--- a/components/sync/driver/sync_service_crypto_unittest.cc
+++ b/components/sync/driver/sync_service_crypto_unittest.cc
@@ -218,6 +218,13 @@
     }
   }
 
+  void RemoveAllStoredKeys() override {
+    gaia_id_to_cached_keys_.clear();
+    for (Observer& observer : observer_list_) {
+      observer.OnTrustedVaultKeysChanged();
+    }
+  }
+
   void MarkKeysAsStale(const CoreAccountInfo& account_info,
                        base::OnceCallback<void(bool)> cb) override {
     const std::string& gaia_id = account_info.gaia;
diff --git a/components/sync/driver/trusted_vault_client.h b/components/sync/driver/trusted_vault_client.h
index af68cc6..f2f46e7 100644
--- a/components/sync/driver/trusted_vault_client.h
+++ b/components/sync/driver/trusted_vault_client.h
@@ -71,6 +71,11 @@
                          const std::vector<std::vector<uint8_t>>& keys,
                          int last_key_version) = 0;
 
+  // Allows implementation to remove all previously stored keys.
+  // Implementations must erase all keys saved during StoreKeys() call. Used
+  // when accounts cookies deleted by the user action.
+  virtual void RemoveAllStoredKeys() = 0;
+
   // Returns whether recoverability of the keys is degraded and user action is
   // required to add a new method. This may be called frequently and
   // implementations are responsible for implementing caching and possibly
diff --git a/components/sync/engine/loopback_server/loopback_server.cc b/components/sync/engine/loopback_server/loopback_server.cc
index 9a4bbd2c..af1e9dd 100644
--- a/components/sync/engine/loopback_server/loopback_server.cc
+++ b/components/sync/engine/loopback_server/loopback_server.cc
@@ -320,6 +320,10 @@
 
   if (message.has_store_birthday() &&
       message.store_birthday() != GetStoreBirthday()) {
+    // The birthday provided by the client does not match the authoritative
+    // value server-side, which in the absence of client-side bugs means that
+    // the birthday was reset (e.g. via ClearServerDataMessage) since the last
+    // time the client interacted with the server.
     response->set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY);
   } else {
     bool success = false;
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto
index 5e9bee2..8ea1fa8 100644
--- a/components/sync/protocol/sync.proto
+++ b/components/sync/protocol/sync.proto
@@ -722,7 +722,9 @@
   reserved "requested_types";
 }
 
-// Message from a client asking the server to clear its data.
+// Message from a client asking the server to clear its data. This causes the
+// server to generate a new store birthday, which allows dealing reliably with
+// in-flight requests (in particular commits) from other clients.
 message ClearServerDataMessage {
   // No arguments needed as the store birthday and user identifier are part of
   // an enclosing message.
@@ -806,7 +808,13 @@
 
   reserved 9;
 
-  optional string store_birthday = 7;  // Opaque store ID; if it changes, duck!
+  // Opaque server-provided ID representing an "epoch" of the server-side data.
+  // Clients must hand this opaque ID back to the server as part of all requests
+  // within the same sync session (i.e. for all requests to the server except
+  // the very first GetUpdates request). See analogous field
+  // ClientToServerResponse.store_birthday for more details about its lifetime.
+  optional string store_birthday = 7;
+
   // The client sets this if it detects a sync issue. The server will tell it
   // if it should perform a refresh.
   optional bool sync_problem_detected = 8 [default = false];
@@ -969,10 +977,16 @@
   optional SyncEnums.ErrorType error_code = 4 [default = UNKNOWN];
   optional string error_message = 5;
 
-  // Opaque store ID; if it changes, the contents of the client's cache
-  // is meaningless to this server.  This happens most typically when
-  // you switch from one storage backend instance (say, a test instance)
-  // to another (say, the official instance).
+  // Opaque server-provided ID representing an "epoch" of the server-side data,
+  // referred to as "birthday" or "store birthday". This ID remains fixed until
+  // server-side data gets cleared/reset (e.g. via ClearServerDataMessage),
+  // which clients experience as NOT_MY_BIRTHDAY error, and involves clearing
+  // all local sync metadata including the cached store birthday.
+  //
+  // This mechanism allows the server to deal reliably with in-flight changes
+  // from other clients upon ClearServerDataMessage (or equivalent triggers),
+  // because all writes issued with an outdated birthday (which in-flight writes
+  // would use) can be detected by the server.
   optional string store_birthday = 6;
 
   optional ClientCommand client_command = 7;
diff --git a/components/sync/protocol/sync_enums.proto b/components/sync/protocol/sync_enums.proto
index 9d417dca..533f5f0 100644
--- a/components/sync/protocol/sync_enums.proto
+++ b/components/sync/protocol/sync_enums.proto
@@ -89,7 +89,9 @@
   enum ErrorType {
     SUCCESS = 0;
     // DEPRECATED_ACCESS_DENIED = 1;
-    // Returned when the server and client disagree on the store birthday.
+    // Returned when the server and client disagree on the store birthday. This
+    // should be interpreted as all local sync metadata requiring cleanup,
+    // obviously including the locally-cached store birthday.
     NOT_MY_BIRTHDAY = 2;
     // Returned when the store has exceeded the allowed bandwidth utilization.
     THROTTLED = 3;
diff --git a/components/sync/protocol/vault.proto b/components/sync/protocol/vault.proto
index ad27b96..fd258590 100644
--- a/components/sync/protocol/vault.proto
+++ b/components/sync/protocol/vault.proto
@@ -6,9 +6,11 @@
 // subtle differences between enum fields.
 syntax = "proto3";
 
+option java_multiple_files = true;
+option java_package = "org.chromium.components.sync.protocol";
+
 option optimize_for = LITE_RUNTIME;
 
-option java_package = "sync_pb";
 package sync_pb;
 
 message SharedMemberKey {
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.h b/components/sync/trusted_vault/standalone_trusted_vault_backend.h
index 0508589..b93947f2 100644
--- a/components/sync/trusted_vault/standalone_trusted_vault_backend.h
+++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.h
@@ -81,8 +81,7 @@
   // |account_info| will trigger a key download attempt.
   bool MarkKeysAsStale(const CoreAccountInfo& account_info);
 
-  // Removes all keys for all accounts from both memory and |file_path_|. Called
-  // when accounts cookie deleted by the user action.
+  // Removes all keys for all accounts from both memory and |file_path_|.
   void RemoveAllStoredKeys();
 
   // Sets/resets |primary_account_|.
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.cc b/components/sync/trusted_vault/standalone_trusted_vault_client.cc
index 20e7b47..4a142209 100644
--- a/components/sync/trusted_vault/standalone_trusted_vault_client.cc
+++ b/components/sync/trusted_vault/standalone_trusted_vault_client.cc
@@ -42,21 +42,20 @@
   return GURL(string_url);
 }
 
-class IdentityManagerObserver : public signin::IdentityManager::Observer {
+class PrimaryAccountObserver : public signin::IdentityManager::Observer {
  public:
-  IdentityManagerObserver(
+  PrimaryAccountObserver(
       scoped_refptr<base::SequencedTaskRunner> backend_task_runner,
       scoped_refptr<StandaloneTrustedVaultBackend> backend,
       signin::IdentityManager* identity_manager);
-  IdentityManagerObserver(const IdentityManagerObserver& other) = delete;
-  IdentityManagerObserver& operator=(const IdentityManagerObserver& other) =
+  PrimaryAccountObserver(const PrimaryAccountObserver& other) = delete;
+  PrimaryAccountObserver& operator=(const PrimaryAccountObserver& other) =
       delete;
-  ~IdentityManagerObserver() override;
+  ~PrimaryAccountObserver() override;
 
   // signin::IdentityManager::Observer implementation.
   void OnPrimaryAccountChanged(
       const signin::PrimaryAccountChangeEvent& event) override;
-  void OnAccountsCookieDeletedByUserAction() override;
 
  private:
   void UpdatePrimaryAccountIfNeeded();
@@ -67,7 +66,7 @@
   CoreAccountInfo primary_account_;
 };
 
-IdentityManagerObserver::IdentityManagerObserver(
+PrimaryAccountObserver::PrimaryAccountObserver(
     scoped_refptr<base::SequencedTaskRunner> backend_task_runner,
     scoped_refptr<StandaloneTrustedVaultBackend> backend,
     signin::IdentityManager* identity_manager)
@@ -82,23 +81,16 @@
   UpdatePrimaryAccountIfNeeded();
 }
 
-IdentityManagerObserver::~IdentityManagerObserver() {
+PrimaryAccountObserver::~PrimaryAccountObserver() {
   identity_manager_->RemoveObserver(this);
 }
 
-void IdentityManagerObserver::OnPrimaryAccountChanged(
+void PrimaryAccountObserver::OnPrimaryAccountChanged(
     const signin::PrimaryAccountChangeEvent& event) {
   UpdatePrimaryAccountIfNeeded();
 }
 
-void IdentityManagerObserver::OnAccountsCookieDeletedByUserAction() {
-  backend_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&StandaloneTrustedVaultBackend::RemoveAllStoredKeys,
-                     backend_));
-}
-
-void IdentityManagerObserver::UpdatePrimaryAccountIfNeeded() {
+void PrimaryAccountObserver::UpdatePrimaryAccountIfNeeded() {
   CoreAccountInfo primary_account =
       identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
   if (primary_account == primary_account_) {
@@ -170,15 +162,15 @@
       FROM_HERE,
       base::BindOnce(&StandaloneTrustedVaultBackend::ReadDataFromDisk,
                      backend_));
-  identity_manager_observer_ = std::make_unique<IdentityManagerObserver>(
+  primary_account_observer_ = std::make_unique<PrimaryAccountObserver>(
       backend_task_runner_, backend_, identity_manager);
 }
 
 StandaloneTrustedVaultClient::~StandaloneTrustedVaultClient() {
   // |backend_| needs to be destroyed inside backend sequence, not the current
-  // one. Destroy |identity_manager_observer_| that owns pointer to |backend_|
+  // one. Destroy |primary_account_observer_| that owns pointer to |backend_|
   // as well and release |backend_| in |backend_task_runner_|.
-  identity_manager_observer_.reset();
+  primary_account_observer_.reset();
   backend_task_runner_->ReleaseSoon(FROM_HERE, std::move(backend_));
 }
 
@@ -217,6 +209,18 @@
   }
 }
 
+void StandaloneTrustedVaultClient::RemoveAllStoredKeys() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(backend_);
+  backend_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&StandaloneTrustedVaultBackend::RemoveAllStoredKeys,
+                     backend_));
+  for (Observer& observer : observer_list_) {
+    observer.OnTrustedVaultKeysChanged();
+  }
+}
+
 void StandaloneTrustedVaultClient::MarkKeysAsStale(
     const CoreAccountInfo& account_info,
     base::OnceCallback<void(bool)> cb) {
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.h b/components/sync/trusted_vault/standalone_trusted_vault_client.h
index 1a198cb0..a9933d0 100644
--- a/components/sync/trusted_vault/standalone_trusted_vault_client.h
+++ b/components/sync/trusted_vault/standalone_trusted_vault_client.h
@@ -60,6 +60,7 @@
   void StoreKeys(const std::string& gaia_id,
                  const std::vector<std::vector<uint8_t>>& keys,
                  int last_key_version) override;
+  void RemoveAllStoredKeys() override;
   void MarkKeysAsStale(const CoreAccountInfo& account_info,
                        base::OnceCallback<void(bool)> cb) override;
   void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
@@ -95,9 +96,9 @@
   // |backend_task_runner_|.
   scoped_refptr<StandaloneTrustedVaultBackend> backend_;
 
-  // Observes changes of accounts state and populates them into |backend_|.
+  // Observes changes of primary account and populates them into |backend_|.
   // Holds references to |backend_| and |backend_task_runner_|.
-  std::unique_ptr<signin::IdentityManager::Observer> identity_manager_observer_;
+  std::unique_ptr<signin::IdentityManager::Observer> primary_account_observer_;
 
   base::WeakPtrFactory<StandaloneTrustedVaultClient> weak_ptr_factory_{this};
 };
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc
index 098523d2..e407397 100644
--- a/components/user_manager/user_manager_base.cc
+++ b/components/user_manager/user_manager_base.cc
@@ -30,6 +30,7 @@
 #include "components/user_manager/remove_user_delegate.h"
 #include "components/user_manager/user_type.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace user_manager {
 namespace {
@@ -954,15 +955,15 @@
 
   const base::DictionaryValue* prefs_oauth_status =
       GetLocalState()->GetDictionary(kUserOAuthTokenStatus);
-  int oauth_token_status = User::OAUTH_TOKEN_STATUS_UNKNOWN;
-  if (prefs_oauth_status &&
-      prefs_oauth_status->GetIntegerWithoutPathExpansion(
-          account_id.GetUserEmail(), &oauth_token_status)) {
-    User::OAuthTokenStatus status =
-        static_cast<User::OAuthTokenStatus>(oauth_token_status);
-    return status;
-  }
-  return User::OAUTH_TOKEN_STATUS_UNKNOWN;
+  if (!prefs_oauth_status)
+    return User::OAUTH_TOKEN_STATUS_UNKNOWN;
+
+  absl::optional<int> oauth_token_status =
+      prefs_oauth_status->FindIntKey(account_id.GetUserEmail());
+  if (!oauth_token_status.has_value())
+    return User::OAUTH_TOKEN_STATUS_UNKNOWN;
+
+  return static_cast<User::OAuthTokenStatus>(oauth_token_status.value());
 }
 
 bool UserManagerBase::LoadForceOnlineSignin(const AccountId& account_id) const {
diff --git a/content/browser/accessibility/accessibility_tree_formatter_utils_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_utils_mac.mm
index 9e659cff..cd3f9b2 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_utils_mac.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_utils_mac.mm
@@ -186,7 +186,10 @@
       property_name == "AXTextMarkerRangeForUIElement") {  // UIElement
     return OptionalNSObject::NotNilOrError(PropertyNodeToUIElement(arg_node));
   }
-  if (property_name == "AXIndexForTextMarker") {  // TextMarker
+  if (property_name == "AXIndexForTextMarker" ||
+      property_name == "AXNextWordEndTextMarkerForTextMarker" ||
+      property_name ==
+          "AXPreviousWordStartTextMarkerForTextMarker") {  // TextMarker
     return OptionalNSObject::NotNilOrError(PropertyNodeToTextMarker(arg_node));
   }
   if (property_name == "AXStringForTextMarkerRange") {  // TextMarkerRange
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 7f10021c..30a50357 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -102,6 +102,8 @@
     NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute =
         @"AXUIElementsForSearchPredicate";
 NSString* const NSAccessibilityVisitedAttribute = @"AXVisited";
+NSString* const NSAccessibilityKeyShortcutsValueAttribute =
+    @"AXKeyShortcutsValue";
 
 // Private attributes for text markers.
 NSString* const NSAccessibilityStartTextMarkerAttribute = @"AXStartTextMarker";
@@ -848,6 +850,7 @@
       {NSAccessibilityLanguageAttribute, @"language"},
       {NSAccessibilityLinkedUIElementsAttribute, @"linkedUIElements"},
       {NSAccessibilityLoadingProgressAttribute, @"loadingProgress"},
+      {NSAccessibilityKeyShortcutsValueAttribute, @"keyShortcutsValue"},
       {NSAccessibilityMaxValueAttribute, @"maxValue"},
       {NSAccessibilityMinValueAttribute, @"minValue"},
       {NSAccessibilityNumberOfCharactersAttribute, @"numberOfCharacters"},
@@ -1723,6 +1726,13 @@
   return @(floatValue);
 }
 
+- (NSString*)keyShortcutsValue {
+  if (![self instanceActive])
+    return nil;
+  return NSStringForStringAttribute(_owner,
+                                    ax::mojom::StringAttribute::kKeyShortcuts);
+}
+
 - (NSNumber*)maxValue {
   if (![self instanceActive])
     return nil;
@@ -3651,6 +3661,9 @@
   if ([self shouldExposeTitleUIElement])
     [ret addObject:NSAccessibilityTitleUIElementAttribute];
 
+  if (_owner->HasStringAttribute(ax::mojom::StringAttribute::kKeyShortcuts))
+    [ret addObject:NSAccessibilityKeyShortcutsValueAttribute];
+
   // TODO(aboxhall): expose NSAccessibilityServesAsTitleForUIElementsAttribute
   // for elements which are referred to by labelledby or are labels
 
diff --git a/content/browser/accessibility/dump_accessibility_node_browsertest.cc b/content/browser/accessibility/dump_accessibility_node_browsertest.cc
index efefb77..1f10791 100644
--- a/content/browser/accessibility/dump_accessibility_node_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_node_browsertest.cc
@@ -717,6 +717,11 @@
   RunAccNameTest(FILE_PATH_LITERAL("name-text-css-before-in-label.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextDynamicLabelledby) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-dynamic-labelledby.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextInputInLabel) {
   RunAccNameTest(FILE_PATH_LITERAL("name-text-input-in-label.html"));
 }
diff --git a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
index 0040e66..bc572ea4 100644
--- a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
@@ -88,6 +88,18 @@
                          ::testing::Values(AXInspectFactory::kMac),
                          TestPassToString());
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest,
+                       AXNextWordEndTextMarkerForTextMarker) {
+  RunMacTextMarkerTest(
+      FILE_PATH_LITERAL("ax-next-word-end-text-marker-for-text-marker.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest,
+                       AXPreviousWordStartTextMarkerForTextMarker) {
+  RunMacTextMarkerTest(FILE_PATH_LITERAL(
+      "ax-previous-word-start-text-marker-for-text-marker.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXStartTextMarker) {
   RunMacTextMarkerTest(FILE_PATH_LITERAL("ax_start_text_marker.html"));
 }
diff --git a/content/browser/conversions/conversion_storage_unittest.cc b/content/browser/conversions/conversion_storage_unittest.cc
index 59e032a..df7a551 100644
--- a/content/browser/conversions/conversion_storage_unittest.cc
+++ b/content/browser/conversions/conversion_storage_unittest.cc
@@ -124,17 +124,7 @@
   EXPECT_EQ(1u, stored_impressions.size());
 
   // Verify that each field was stored as expected.
-  EXPECT_EQ(impression.impression_data(),
-            stored_impressions[0].impression_data());
-  EXPECT_EQ(impression.impression_origin(),
-            stored_impressions[0].impression_origin());
-  EXPECT_EQ(impression.conversion_origin(),
-            stored_impressions[0].conversion_origin());
-  EXPECT_EQ(impression.reporting_origin(),
-            stored_impressions[0].reporting_origin());
-  EXPECT_EQ(impression.impression_time(),
-            stored_impressions[0].impression_time());
-  EXPECT_EQ(impression.expiry_time(), stored_impressions[0].expiry_time());
+  EXPECT_TRUE(ImpressionsEqual(impression, stored_impressions[0]));
 }
 
 TEST_F(ConversionStorageTest,
diff --git a/content/browser/conversions/impression_declaration_browsertest.cc b/content/browser/conversions/impression_declaration_browsertest.cc
index c1555e9..3cba023 100644
--- a/content/browser/conversions/impression_declaration_browsertest.cc
+++ b/content/browser/conversions/impression_declaration_browsertest.cc
@@ -833,8 +833,10 @@
   EXPECT_EQ(10, last_impression.priority);
 }
 
-IN_PROC_BROWSER_TEST_F(ImpressionDeclarationBrowserTest,
-                       WindowOpenAttributionSourceFeatures_FeaturesHandled) {
+// TODO(crbug.com/1215063): Flaky timeout on serveral builders.
+IN_PROC_BROWSER_TEST_F(
+    ImpressionDeclarationBrowserTest,
+    DISABLED_WindowOpenAttributionSourceFeatures_FeaturesHandled) {
   struct {
     std::string features;
     bool expected;
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.h b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
index bfcd03de..3d68f96 100644
--- a/content/browser/renderer_host/render_frame_metadata_provider_impl.h
+++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
@@ -60,6 +60,7 @@
 
  private:
   friend class FakeRenderWidgetHostViewAura;
+  friend class DelegatedInkPointTest;
 
   // Paired with the mojom::RenderFrameMetadataObserverClient overrides, these
   // methods are enqueued in |frame_token_message_queue_|. They are invoked when
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 893c804..b2e08a8 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/hit_test/hit_test_region_list.h"
 #include "components/viz/common/quads/surface_draw_quad.h"
@@ -27,6 +28,7 @@
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "ui/base/layout.h"
+#include "ui/compositor/compositor.h"
 #include "ui/gfx/geometry/dip_util.h"
 
 namespace {
@@ -641,6 +643,14 @@
     mouse_capture_target_ = target;
   }
 
+  if (target) {
+    ui::EventType type = mouse_event.GetTypeAsUiEventType();
+    bool hovering =
+        (type ^ ui::ET_MOUSE_DRAGGED) && (type ^ ui::ET_MOUSE_PRESSED);
+    ForwardDelegatedInkPoint(target, root_view, mouse_event, mouse_event,
+                             hovering);
+  }
+
   DCHECK(target_location.has_value());
   blink::WebMouseEvent event = mouse_event;
   event.SetPositionInWidget(target_location->x(), target_location->y());
@@ -865,6 +875,11 @@
     base::debug::DumpWithoutCrashing();
   }
 
+  if (touch_target_) {
+    ForwardDelegatedInkPoint(touch_target_, root_view, touch_event,
+                             touch_event.touches[0], touch_event.hovering);
+  }
+
   TouchEventAckQueue::TouchEventSource event_source =
       is_emulated_touchevent
           ? TouchEventAckQueue::TouchEventSource::EmulatedTouchEvent
@@ -1988,4 +2003,71 @@
   event_targeter_->SetIsAutoScrollInProgress(is_autoscroll_in_progress);
 }
 
+bool IsMoveEvent(ui::EventType type) {
+  return type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED ||
+         type == ui::ET_TOUCH_MOVED;
+}
+
+void RenderWidgetHostInputEventRouter::ForwardDelegatedInkPoint(
+    RenderWidgetHostViewBase* target_view,
+    RenderWidgetHostViewBase* root_view,
+    const blink::WebInputEvent& input_event,
+    const blink::WebPointerProperties& pointer_properties,
+    bool hovering) {
+  const absl::optional<cc::DelegatedInkBrowserMetadata>& metadata =
+      target_view->host()
+          ->render_frame_metadata_provider()
+          ->LastRenderFrameMetadata()
+          .delegated_ink_metadata;
+
+  if (IsMoveEvent(input_event.GetTypeAsUiEventType()) && metadata &&
+      hovering == metadata.value().delegated_ink_is_hovering) {
+    if (!delegated_ink_point_renderer_.is_bound()) {
+      ui::Compositor* compositor = target_view->GetCompositor();
+
+      // The remote can't be bound if the compositor is null, so bail if that
+      // is the case so we don't crash by trying to use an unbound remote.
+      if (!compositor)
+        return;
+
+      TRACE_EVENT_INSTANT0("input",
+                           "Binding mojo interface for delegated ink points.",
+                           TRACE_EVENT_SCOPE_THREAD);
+      compositor->SetDelegatedInkPointRenderer(
+          delegated_ink_point_renderer_.BindNewPipeAndPassReceiver());
+      delegated_ink_point_renderer_.reset_on_disconnect();
+    }
+
+    gfx::PointF position = pointer_properties.PositionInWidget();
+    root_view->TransformPointToRootSurface(&position);
+    position.Scale(target_view->GetDeviceScaleFactor());
+
+    gfx::DelegatedInkPoint delegated_ink_point(
+        position, input_event.TimeStamp(), pointer_properties.id);
+    TRACE_EVENT_INSTANT1("input",
+                         "Forwarding delegated ink point from browser.",
+                         TRACE_EVENT_SCOPE_THREAD, "delegated point",
+                         delegated_ink_point.ToString());
+
+    // Calling this will result in IPC calls to get |delegated_ink_point| to
+    // viz. The decision to do this here was made with the understanding that
+    // the IPC overhead will result in a minor increase in latency for getting
+    // this event to the renderer. However, by sending it here, the event is
+    // given the greatest possible chance to make it to viz before
+    // DrawAndSwap() is called, allowing more points to be drawn as part of
+    // the delegated ink trail, and thus reducing user perceived latency.
+    delegated_ink_point_renderer_->StoreDelegatedInkPoint(delegated_ink_point);
+    ended_delegated_ink_trail_ = false;
+  } else if (delegated_ink_point_renderer_.is_bound() &&
+             !ended_delegated_ink_trail_) {
+    // Let viz know that the most recent point it received from us is probably
+    // the last point the user is inking, so it shouldn't predict anything
+    // beyond it.
+    TRACE_EVENT_INSTANT0("input", "Delegated ink trail ended",
+                         TRACE_EVENT_SCOPE_THREAD);
+    delegated_ink_point_renderer_->ResetPrediction();
+    ended_delegated_ink_trail_ = true;
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index 3550833..b850e9e 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -23,8 +23,10 @@
 #include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
 #include "content/browser/renderer_host/render_widget_targeter.h"
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
 #include "ui/gfx/transform.h"
 
 namespace blink {
@@ -32,6 +34,7 @@
 class WebInputEvent;
 class WebMouseEvent;
 class WebMouseWheelEvent;
+class WebPointerProperties;
 class WebTouchEvent;
 }
 
@@ -332,6 +335,18 @@
   void SetTouchscreenGestureTarget(RenderWidgetHostViewBase* target,
                                    bool moved_recently = false);
 
+  void ForwardDelegatedInkPoint(
+      RenderWidgetHostViewBase* target_view,
+      RenderWidgetHostViewBase* root_view,
+      const blink::WebInputEvent& input_event,
+      const blink::WebPointerProperties& pointer_properties,
+      bool hovering);
+
+  void FlushForTest() { delegated_ink_point_renderer_.FlushForTesting(); }
+  bool IsDelegatedInkRendererBoundForTest() {
+    return delegated_ink_point_renderer_.is_bound();
+  }
+
   FrameSinkIdOwnerMap owner_map_;
   TargetMap touchscreen_gesture_target_map_;
   RenderWidgetHostViewBase* touch_target_ = nullptr;
@@ -429,6 +444,18 @@
   // Used to prevent multiple dumps.
   bool has_dumped_ = false;
 
+  // Remote end of the connection for sending delegated ink points to viz to
+  // support the delegated ink trails feature.
+  mojo::Remote<gfx::mojom::DelegatedInkPointRenderer>
+      delegated_ink_point_renderer_;
+  // Used to know if we have already told viz to reset prediction because the
+  // final point of the delegated ink trail has been sent. True when prediction
+  // has already been reset for the most recent trail, false otherwise. This
+  // flag helps make sure that we don't send more IPCs than necessary to viz to
+  // reset prediction. Sending extra IPCs wouldn't impact correctness, but can
+  // impact performance due to the IPC overhead.
+  bool ended_delegated_ink_trail_ = false;
+
   base::WeakPtrFactory<RenderWidgetHostInputEventRouter> weak_ptr_factory_{
       this};
 
@@ -450,6 +477,8 @@
                            InputEventRouterWheelTargetTest);
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessMacBrowserTest,
                            InputEventRouterTouchpadGestureTargetTest);
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessDelegatedInkBrowserTest,
+                           MetadataAndPointGoThroughOOPIF);
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
index fe41ab1f..9db386e 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
@@ -31,6 +31,13 @@
 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
 #include "third_party/blink/public/mojom/input/touch_event.mojom.h"
 
+#if defined(USE_AURA)
+#include "ui/aura/test/aura_test_helper.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
+#endif  // defined(USE_AURA)
+
 namespace content {
 
 namespace {
@@ -100,10 +107,15 @@
 
   void Reset() { last_gesture_seen_ = blink::WebInputEvent::Type::kUndefined; }
 
+  void SetCompositor(ui::Compositor* compositor) { compositor_ = compositor; }
+  ui::Compositor* GetCompositor() override { return compositor_; }
+
  private:
   blink::WebInputEvent::Type last_gesture_seen_ =
       blink::WebInputEvent::Type::kUndefined;
   uint32_t unique_id_for_last_touch_ack_ = 0;
+
+  ui::Compositor* compositor_;
 };
 
 class StubHitTestQuery : public viz::HitTestQuery {
@@ -336,6 +348,8 @@
       RenderWidgetHostViewBase* gesture_target,
       bool should_cancel);
 
+  void FlushInkRenderer() { rwhier()->FlushForTest(); }
+
   BrowserTaskEnvironment task_environment_;
 
   MockRenderWidgetHostDelegate delegate_;
@@ -1045,4 +1059,505 @@
   base::RunLoop().RunUntilIdle();
 }
 
+#if defined(USE_AURA)
+// Mock the DelegatedInkPointRenderer to grab the delegated ink points as they
+// are shipped off to viz from the browser process.
+class MockDelegatedInkPointRenderer
+    : public gfx::mojom::DelegatedInkPointRenderer {
+ public:
+  explicit MockDelegatedInkPointRenderer(
+      mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver)
+      : receiver_(this, std::move(receiver)) {}
+
+  void StoreDelegatedInkPoint(const gfx::DelegatedInkPoint& point) override {
+    delegated_ink_point_ = point;
+  }
+
+  bool HasDelegatedInkPoint() { return delegated_ink_point_.has_value(); }
+
+  gfx::DelegatedInkPoint GetDelegatedInkPoint() {
+    gfx::DelegatedInkPoint point = delegated_ink_point_.value();
+    delegated_ink_point_.reset();
+    return point;
+  }
+
+  void ClearDelegatedInkPoint() { delegated_ink_point_.reset(); }
+
+  void ResetPrediction() override { prediction_reset_ = true; }
+  bool GetPredictionState() {
+    bool state = prediction_reset_;
+    prediction_reset_ = false;
+    return state;
+  }
+
+  void FlushForTesting() { receiver_.FlushForTesting(); }
+
+  void ResetReceiver() { receiver_.reset(); }
+  bool ReceiverIsBound() { return receiver_.is_bound(); }
+
+ private:
+  mojo::Receiver<gfx::mojom::DelegatedInkPointRenderer> receiver_;
+  absl::optional<gfx::DelegatedInkPoint> delegated_ink_point_;
+  bool prediction_reset_ = false;
+};
+
+// MockCompositor class binds the mojo interfaces so that the ink points are
+// shipped to the browser process. Uses values from the real compositor to be
+// created, but a fake FrameSinkId must be used so that it hasn't already been
+// registered.
+class MockCompositor : public ui::Compositor {
+ public:
+  explicit MockCompositor(ui::Compositor* compositor)
+      : ui::Compositor(viz::FrameSinkId(5, 5),
+                       compositor->context_factory(),
+                       compositor->task_runner(),
+                       compositor->is_pixel_canvas()) {}
+
+  void SetDelegatedInkPointRenderer(
+      mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver)
+      override {
+    delegated_ink_point_renderer_ =
+        std::make_unique<MockDelegatedInkPointRenderer>(std::move(receiver));
+  }
+
+  MockDelegatedInkPointRenderer* delegated_ink_point_renderer() {
+    return delegated_ink_point_renderer_.get();
+  }
+
+ private:
+  std::unique_ptr<MockDelegatedInkPointRenderer> delegated_ink_point_renderer_;
+};
+
+enum TestEvent { kMouseEvent, kTouchEvent };
+enum HoveringState { kHovering, kNotHovering };
+
+class DelegatedInkPointTest
+    : public RenderWidgetHostInputEventRouterTest,
+      public testing::WithParamInterface<std::tuple<TestEvent, HoveringState>> {
+ public:
+  DelegatedInkPointTest() = default;
+
+  void SetUp() override {
+    RenderWidgetHostInputEventRouterTest::SetUp();
+
+    aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>(
+        ImageTransportFactory::GetInstance()->GetContextFactory());
+    aura_test_helper_->SetUp();
+
+    compositor_ = std::make_unique<MockCompositor>(
+        aura_test_helper_->GetHost()->compositor());
+    view_root_->SetCompositor(compositor_.get());
+  }
+
+  void TearDown() override {
+    aura_test_helper_->TearDown();
+    compositor_.reset();
+    RenderWidgetHostInputEventRouterTest::TearDown();
+  }
+
+  TestEvent GetEventParam() { return std::get<0>(GetParam()); }
+  HoveringState GetHoverParam() { return std::get<1>(GetParam()); }
+
+  void SetInkMetadataFlagOnRenderFrameMetadata(bool delegated_ink) {
+    SetInkMetadataFlagOnSpecificHost(delegated_ink, widget_host_root_.get());
+  }
+
+  void SetInkMetadataFlagOnSpecificHost(bool delegated_ink,
+                                        RenderWidgetHostImpl* widget_host) {
+    cc::RenderFrameMetadata metadata;
+    if (delegated_ink) {
+      metadata.delegated_ink_metadata = cc::DelegatedInkBrowserMetadata(
+          GetHoverParam() == HoveringState::kHovering);
+    }
+    widget_host->render_frame_metadata_provider()
+        ->SetLastRenderFrameMetadataForTest(metadata);
+  }
+
+  void SendEvent(bool match_test_hovering_state,
+                 gfx::PointF point,
+                 base::TimeTicks timestamp = base::TimeTicks::Now()) {
+    SendEvent(match_test_hovering_state, point, timestamp,
+              /*use_enter_event*/ false, /*use_exit_event*/ false);
+  }
+
+  void SendEvent(bool match_test_hovering_state,
+                 const gfx::PointF& point,
+                 base::TimeTicks timestamp,
+                 bool use_enter_event,
+                 bool use_exit_event) {
+    DCHECK(!(use_enter_event && use_exit_event));
+
+    // Hovering creates and sends ui::MouseEvents with
+    // ET_MOUSE_{MOVED,ENTERED,EXITED} types, so do the same here in hovering
+    // scenarios.
+    if (GetEventParam() == TestEvent::kTouchEvent &&
+        !Hovering(match_test_hovering_state)) {
+      blink::WebInputEvent::Type event_type =
+          blink::WebInputEvent::Type::kTouchMove;
+      blink::WebTouchPoint::State touch_state =
+          blink::WebTouchPoint::State::kStateMoved;
+      if (use_enter_event) {
+        event_type = blink::WebInputEvent::Type::kTouchStart;
+        touch_state = blink::WebTouchPoint::State::kStatePressed;
+        // Set this now so that if we are going to send a enter event anyway,
+        // we don't send two.
+        sent_touch_press_ = true;
+      }
+      if (use_exit_event) {
+        event_type = blink::WebInputEvent::Type::kTouchEnd;
+        touch_state = blink::WebTouchPoint::State::kStateReleased;
+      }
+
+      // Touch needs a pressed event first to properly handle future move
+      // events.
+      SendTouchPress(point);
+
+      blink::WebTouchEvent touch_event(
+          event_type, blink::WebInputEvent::kNoModifiers, timestamp);
+      touch_event.touches_length = 1;
+      touch_event.touches[0].id = kPointerId;
+      touch_event.touches[0].SetPositionInWidget(point);
+      touch_event.touches[0].state = touch_state;
+      touch_event.unique_touch_event_id = GetTouchId();
+
+      rwhier()->RouteTouchEvent(view_root_.get(), &touch_event,
+                                ui::LatencyInfo(ui::SourceEventType::TOUCH));
+
+      // Need to send a new press event after ending the previous touch.
+      if (use_exit_event)
+        sent_touch_press_ = false;
+    } else {
+      blink::WebInputEvent::Type event_type =
+          blink::WebInputEvent::Type::kMouseMove;
+      if (use_enter_event)
+        event_type = blink::WebInputEvent::Type::kMouseEnter;
+      if (use_exit_event)
+        event_type = blink::WebInputEvent::Type::kMouseLeave;
+
+      int modifiers = 0;
+      if (!Hovering(match_test_hovering_state))
+        modifiers = blink::WebInputEvent::kLeftButtonDown;
+
+      blink::WebMouseEvent mouse_event(event_type, modifiers, timestamp,
+                                       kPointerId);
+      mouse_event.SetPositionInWidget(point);
+
+      rwhier()->RouteMouseEvent(view_root_.get(), &mouse_event,
+                                ui::LatencyInfo(ui::SourceEventType::MOUSE));
+    }
+  }
+
+  void SetDeviceScaleFactor(float dsf) {
+    aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(dsf);
+  }
+
+  MockCompositor* compositor() { return compositor_.get(); }
+
+  int32_t GetExpectedPointerId() const { return kPointerId; }
+
+ private:
+  void SendTouchPress(const gfx::PointF& requested_touch_location) {
+    DCHECK(GetEventParam() == TestEvent::kTouchEvent);
+    if (sent_touch_press_)
+      return;
+
+    // Location of the press event doesn't matter, so long as it doesn't exactly
+    // match the location of the subsequent move event. If they match, then the
+    // move event is dropped.
+    gfx::PointF point(requested_touch_location.x() + 2.f,
+                      requested_touch_location.y() + 2.f);
+
+    // Send a TouchStart/End sequence.
+    blink::WebTouchEvent press(
+        blink::WebInputEvent::Type::kTouchStart,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::GetStaticTimeStampForTests());
+    press.touches_length = 1;
+    press.touches[0].id = kPointerId;
+    press.touches[0].SetPositionInWidget(point);
+    press.touches[0].state = blink::WebTouchPoint::State::kStatePressed;
+    press.unique_touch_event_id = GetTouchId();
+
+    rwhier()->RouteTouchEvent(view_root_.get(), &press,
+                              ui::LatencyInfo(ui::SourceEventType::TOUCH));
+    sent_touch_press_ = true;
+  }
+
+  bool Hovering(bool match_test_hovering_state) {
+    return (GetHoverParam() == HoveringState::kHovering &&
+            match_test_hovering_state) ||
+           (GetHoverParam() == HoveringState::kNotHovering &&
+            !match_test_hovering_state);
+  }
+
+  // Unique touch id is unique per event, so always increment before providing
+  // a new one.
+  int GetTouchId() { return ++unique_touch_id_; }
+
+  // Pointer id to use in these tests. It must be consistent throughout a single
+  // test for some of the touch variations.
+  const int32_t kPointerId = 5;
+
+  // Touch events are ignored if a press isn't sent first, so use this to track
+  // if we have already sent a touch press event yet or not.
+  bool sent_touch_press_ = false;
+
+  // Most recently used unique touch id for blink::WebTouchEvents
+  int unique_touch_id_ = 0;
+
+  // Helper for creating a compositor and setting the device scale factor.
+  std::unique_ptr<aura::test::AuraTestHelper> aura_test_helper_;
+
+  // Mock compositor used for getting the delegated ink points that are
+  // forwarded.
+  std::unique_ptr<MockCompositor> compositor_;
+};
+
+struct DelegatedInkPointTestPassToString {
+  std::string operator()(
+      const testing::TestParamInfo<std::tuple<TestEvent, HoveringState>> type)
+      const {
+    std::string suffix;
+
+    if (std::get<0>(type.param) == TestEvent::kMouseEvent)
+      suffix.append("Mouse");
+    else
+      suffix.append("Touch");
+
+    if (std::get<1>(type.param) == HoveringState::kHovering)
+      suffix.append("Hovering");
+    else
+      suffix.append("NotHovering");
+
+    return suffix;
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    DelegatedInkTrails,
+    DelegatedInkPointTest,
+    testing::Combine(
+        testing::Values(TestEvent::kMouseEvent, TestEvent::kTouchEvent),
+        testing::Values(HoveringState::kHovering, HoveringState::kNotHovering)),
+    DelegatedInkPointTestPassToString());
+
+// Tests to confirm that input events are correctly forwarded to the UI
+// Compositor when DelegatedInkTrails should be drawn, and stops forwarding when
+// they no longer should be drawn.
+TEST_P(DelegatedInkPointTest, EventForwardedToCompositor) {
+  // First confirm that the flag is false by default and the point is not sent.
+  SendEvent(true, gfx::PointF(15, 15));
+  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
+      compositor()->delegated_ink_point_renderer();
+
+  EXPECT_FALSE(delegated_ink_point_renderer);
+
+  // Then set it to true and confirm that the DelegatedInkPointRenderer is
+  // initialized, the connection is made and the point makes it to the renderer.
+  SetInkMetadataFlagOnRenderFrameMetadata(true);
+  gfx::DelegatedInkPoint expected_point(
+      gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId());
+  SendEvent(true, expected_point.point(), expected_point.timestamp());
+
+  delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer();
+  EXPECT_TRUE(delegated_ink_point_renderer);
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  gfx::DelegatedInkPoint actual_point =
+      delegated_ink_point_renderer->GetDelegatedInkPoint();
+  EXPECT_EQ(expected_point.point(), actual_point.point());
+  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
+  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
+
+  // Then try changing the scale factor to confirm it affects the point
+  // correctly.
+  const float scale = 2.6f;
+  SetDeviceScaleFactor(scale);
+  gfx::PointF unscaled_point(15, 15);
+  base::TimeTicks unscaled_time = base::TimeTicks::Now();
+
+  SendEvent(true, unscaled_point, unscaled_time);
+  delegated_ink_point_renderer->FlushForTesting();
+
+  unscaled_point.Scale(scale);
+  expected_point = gfx::DelegatedInkPoint(unscaled_point, unscaled_time,
+                                          GetExpectedPointerId());
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint();
+  EXPECT_EQ(expected_point.point(), actual_point.point());
+  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
+  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
+
+  // Confirm that prediction is reset when the API is no longer being used and
+  // |delegated_ink_metadata| is not set.
+  SetInkMetadataFlagOnRenderFrameMetadata(false);
+
+  SendEvent(true, gfx::PointF(25, 25));
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState());
+
+  // Finally, confirm that nothing is sent after the prediction has been reset
+  // when the delegated ink flag on the render frame metadata is false.
+  SendEvent(true, gfx::PointF(46, 46));
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState());
+}
+
+// Confirm that the interface is rebound if the receiver disconnects.
+TEST_P(DelegatedInkPointTest, MojoInterfaceReboundOnDisconnect) {
+  // First make sure the connection exists.
+  SetInkMetadataFlagOnRenderFrameMetadata(true);
+  SendEvent(true, gfx::PointF(15, 15));
+
+  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
+      compositor()->delegated_ink_point_renderer();
+
+  EXPECT_TRUE(delegated_ink_point_renderer);
+  EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound());
+
+  // Reset the receiver and flush the remote to confirm it is no longer bound.
+  delegated_ink_point_renderer->ResetReceiver();
+  FlushInkRenderer();
+
+  EXPECT_FALSE(delegated_ink_point_renderer->ReceiverIsBound());
+
+  // Confirm that it now gets reconnected correctly.
+  SendEvent(true, gfx::PointF(25, 25));
+
+  delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer();
+
+  EXPECT_TRUE(delegated_ink_point_renderer);
+  EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound());
+}
+
+// Test to confirm that forwarding points to viz will stop and prediction is
+// reset if the state of hovering differs between what is expected and the
+// received points.
+TEST_P(DelegatedInkPointTest, StopForwardingOnHoverStateChange) {
+  // First send a point and make sure it makes it to the renderer.
+  SetInkMetadataFlagOnRenderFrameMetadata(true);
+  SendEvent(true, gfx::PointF(15, 15));
+
+  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
+      compositor()->delegated_ink_point_renderer();
+  EXPECT_TRUE(delegated_ink_point_renderer);
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  delegated_ink_point_renderer->ClearDelegatedInkPoint();
+
+  // Now send a point that doesn't match the state of hovering on the metadata
+  // to confirm that it isn't sent and ResetPrediction is called.
+  SendEvent(false, gfx::PointF(20, 20));
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState());
+
+  // Send another that doesn't match to confirm the end trail point is only sent
+  // once.
+  SendEvent(false, gfx::PointF(25, 25));
+  delegated_ink_point_renderer->FlushForTesting();
+  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+
+  // Send one that does match again to confirm that points will start sending
+  // again if the hovering state starts matching again.
+  SendEvent(true, gfx::PointF(30, 30));
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState());
+}
+
+// Confirm that only move events are forwarded, not enter/exit or equivalent
+// events.
+TEST_P(DelegatedInkPointTest, IgnoreEnterAndExitEvents) {
+  // First set everything up and try forwarding a point, confirming that it is
+  // sent as expected.
+  SetInkMetadataFlagOnRenderFrameMetadata(true);
+  gfx::DelegatedInkPoint expected_point(
+      gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId());
+  SendEvent(true, expected_point.point(), expected_point.timestamp());
+
+  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
+      compositor()->delegated_ink_point_renderer();
+  EXPECT_TRUE(delegated_ink_point_renderer);
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  gfx::DelegatedInkPoint actual_point =
+      delegated_ink_point_renderer->GetDelegatedInkPoint();
+  EXPECT_EQ(expected_point.point(), actual_point.point());
+  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
+  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
+
+  // Now try with an exit event.
+  SendEvent(true, gfx::PointF(42, 19), base::TimeTicks::Now(),
+            /*use_enter_event=*/false, /*use_exit_event=*/true);
+  delegated_ink_point_renderer->FlushForTesting();
+  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+
+  // Try sending an enter event and confirm it is not forwarded.
+  SendEvent(true, gfx::PointF(12, 12), base::TimeTicks::Now(),
+            /*use_enter_event=*/true, /*use_exit_event=*/false);
+  delegated_ink_point_renderer->FlushForTesting();
+  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+
+  // Finally, confirm that sending move events will work again without issue.
+  expected_point = gfx::DelegatedInkPoint(
+      gfx::PointF(20, 21), base::TimeTicks::Now(), GetExpectedPointerId());
+  SendEvent(true, expected_point.point(), expected_point.timestamp());
+
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint();
+  EXPECT_EQ(expected_point.point(), actual_point.point());
+  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
+  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
+}
+
+// This test confirms that points can be forwarded when using delegated ink in
+// a child frame, such as an OOPIF.
+TEST_P(DelegatedInkPointTest, ForwardPointsToChildFrame) {
+  // Make the child frame, set the delegated ink flag on it, give it a
+  // compositor, and set it as the hit test result so that the input router
+  // sends points to it.
+  ChildViewState child = MakeChildView(view_root_.get());
+  SetInkMetadataFlagOnSpecificHost(true, child.widget_host.get());
+  child.view->SetCompositor(compositor());
+  view_root_->SetHittestResult(child.view.get(), false);
+
+  // Send a point and confirm that it is forwarded, meaning that it correctly
+  // checked the metadata flag on the child frame's widget.
+  gfx::DelegatedInkPoint expected_point(
+      gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId());
+  SendEvent(true, expected_point.point(), expected_point.timestamp(), false,
+            false);
+
+  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
+      compositor()->delegated_ink_point_renderer();
+  EXPECT_TRUE(delegated_ink_point_renderer);
+  delegated_ink_point_renderer->FlushForTesting();
+
+  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
+  gfx::DelegatedInkPoint actual_point =
+      delegated_ink_point_renderer->GetDelegatedInkPoint();
+  EXPECT_EQ(expected_point.point(), actual_point.point());
+  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
+  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
+
+  // Reset's the hit test result on the root so that we don't crash on
+  // destruction.
+  rwhier()->OnRenderWidgetHostViewBaseDestroyed(child.view.get());
+}
+
+#endif  // defined(USE_AURA)
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index d8365d0..053eaaf 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1855,10 +1855,10 @@
 }
 
 viz::FrameSinkId RenderWidgetHostViewAura::GetRootFrameSinkId() {
-  if (!window_ || !window_->GetHost() || !window_->GetHost()->compositor())
+  if (!GetCompositor())
     return viz::FrameSinkId();
 
-  return window_->GetHost()->compositor()->frame_sink_id();
+  return GetCompositor()->frame_sink_id();
 }
 
 viz::SurfaceId RenderWidgetHostViewAura::GetCurrentSurfaceId() const {
@@ -2377,7 +2377,7 @@
   UpdateLegacyWin();
 #endif
 
-    delegated_frame_host_->AttachToCompositor(window_->GetHost()->compositor());
+  delegated_frame_host_->AttachToCompositor(GetCompositor());
 }
 
 void RenderWidgetHostViewAura::RemovingFromRootWindow() {
@@ -2730,4 +2730,11 @@
     tooltip_observer_for_testing_->OnTooltipTextUpdated(tooltip_text);
 }
 
+ui::Compositor* RenderWidgetHostViewAura::GetCompositor() {
+  if (!window_ || !window_->GetHost())
+    return nullptr;
+
+  return window_->GetHost()->compositor();
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index b881bdc..ea2aee1 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -373,6 +373,8 @@
 
   MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override;
 
+  ui::Compositor* GetCompositor() override;
+
  protected:
   ~RenderWidgetHostViewAura() override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 466e96ff..a90ac41 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -120,7 +120,6 @@
 #include "ui/events/keycodes/keyboard_code_conversion.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
 #include "ui/gfx/selection_bound.h"
 #include "ui/wm/core/window_util.h"
 
@@ -286,9 +285,6 @@
     return event_handler()->pointer_state();
   }
 
-  // Flush the mojo remote on the event handler for testing purposes.
-  void FlushForTest() { event_handler()->FlushForTest(); }
-
   void SetRenderFrameMetadata(cc::RenderFrameMetadata metadata) {
     host()->render_frame_metadata_provider()->SetLastRenderFrameMetadataForTest(
         metadata);
@@ -6758,428 +6754,4 @@
 
 #endif  // defined(OS_WIN)
 
-// Mock the DelegatedInkPointRenderer to grab the delegated ink points as they
-// are shipped off to viz from the browser process.
-class MockDelegatedInkPointRenderer
-    : public gfx::mojom::DelegatedInkPointRenderer {
- public:
-  explicit MockDelegatedInkPointRenderer(
-      mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver)
-      : receiver_(this, std::move(receiver)) {}
-
-  void StoreDelegatedInkPoint(const gfx::DelegatedInkPoint& point) override {
-    delegated_ink_point_ = point;
-  }
-
-  bool HasDelegatedInkPoint() { return delegated_ink_point_.has_value(); }
-
-  gfx::DelegatedInkPoint GetDelegatedInkPoint() {
-    gfx::DelegatedInkPoint point = delegated_ink_point_.value();
-    delegated_ink_point_.reset();
-    return point;
-  }
-
-  void ClearDelegatedInkPoint() { delegated_ink_point_.reset(); }
-
-  void ResetPrediction() override { prediction_reset_ = true; }
-  bool GetPredictionState() {
-    bool state = prediction_reset_;
-    prediction_reset_ = false;
-    return state;
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
-  void ResetReceiver() { receiver_.reset(); }
-  bool ReceiverIsBound() { return receiver_.is_bound(); }
-
- private:
-  mojo::Receiver<gfx::mojom::DelegatedInkPointRenderer> receiver_;
-  absl::optional<gfx::DelegatedInkPoint> delegated_ink_point_;
-  bool prediction_reset_ = false;
-};
-
-// MockCompositor class binds the mojo interfaces so that the ink points are
-// shipped to the browser process. Uses values from the real compositor to be
-// created, but a fake FrameSinkId must be used so that it hasn't already been
-// registered.
-class MockCompositor : public ui::Compositor {
- public:
-  explicit MockCompositor(ui::Compositor* compositor)
-      : ui::Compositor(viz::FrameSinkId(5, 5),
-                       compositor->context_factory(),
-                       compositor->task_runner(),
-                       compositor->is_pixel_canvas()) {}
-
-  void SetDelegatedInkPointRenderer(
-      mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver)
-      override {
-    delegated_ink_point_renderer_ =
-        std::make_unique<MockDelegatedInkPointRenderer>(std::move(receiver));
-  }
-
-  MockDelegatedInkPointRenderer* delegated_ink_point_renderer() {
-    return delegated_ink_point_renderer_.get();
-  }
-
- private:
-  std::unique_ptr<MockDelegatedInkPointRenderer> delegated_ink_point_renderer_;
-};
-
-enum TestEvent { kMouseEvent, kTouchEvent };
-enum HoveringState { kHovering, kNotHovering };
-
-class DelegatedInkPointTest
-    : public RenderWidgetHostViewAuraTest,
-      public testing::WithParamInterface<std::tuple<TestEvent, HoveringState>> {
- public:
-  DelegatedInkPointTest() = default;
-
-  void SetUp() override {
-    RenderWidgetHostViewAuraTest::SetUp();
-
-    InitViewForFrame(nullptr);
-    aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(1.0f);
-
-    real_compositor_ = view_->GetNativeView()->layer()->GetCompositor();
-    compositor_ = std::make_unique<MockCompositor>(
-        aura_test_helper_->GetHost()->compositor());
-    view_->GetNativeView()->layer()->SetCompositorForTesting(compositor_.get());
-  }
-
-  void TearDown() override {
-    // Restore the view's compositor to the old value so it no longer references
-    // the MockCompositor that is about to be destructed. This also ensures
-    // that the view can be properly destroyed by TearDown().
-    view_->GetNativeView()->layer()->SetCompositorForTesting(real_compositor_);
-    compositor_.reset();
-    RenderWidgetHostViewAuraTest::TearDown();
-  }
-
-  TestEvent GetEventParam() { return std::get<0>(GetParam()); }
-  HoveringState GetHoverParam() { return std::get<1>(GetParam()); }
-
-  void SetInkMetadataFlagOnRenderFrameMetadata(bool delegated_ink) {
-    cc::RenderFrameMetadata metadata;
-    if (delegated_ink) {
-      metadata.delegated_ink_metadata = cc::DelegatedInkBrowserMetadata(
-          GetHoverParam() == HoveringState::kHovering);
-    }
-    view_->SetRenderFrameMetadata(metadata);
-  }
-
-  void SendEvent(bool match_test_hovering_state,
-                 gfx::PointF point,
-                 base::TimeTicks timestamp = ui::EventTimeForNow()) {
-    SendEvent(match_test_hovering_state, point, timestamp,
-              /*use_enter_event*/ false, /*use_exit_event*/ false);
-  }
-
-  void SendEvent(bool match_test_hovering_state,
-                 const gfx::PointF& point,
-                 base::TimeTicks timestamp,
-                 bool use_enter_event,
-                 bool use_exit_event) {
-    DCHECK(!(use_enter_event && use_exit_event));
-
-    // Hovering creates and sends ui::MouseEvents with
-    // ET_MOUSE_{MOVED,ENTERED,EXITED} types, so do the same here in hovering
-    // scenarios.
-    if (GetEventParam() == TestEvent::kTouchEvent &&
-        !Hovering(match_test_hovering_state)) {
-      ui::EventType event_type = ui::ET_TOUCH_MOVED;
-      if (use_enter_event)
-        event_type = ui::ET_TOUCH_PRESSED;
-      if (use_exit_event)
-        event_type = ui::ET_TOUCH_RELEASED;
-
-      // Touch needs a pressed event first to properly handle future move
-      // events.
-      SendTouchPress(point);
-
-      ui::TouchEvent touch_event(
-          event_type, point, point, timestamp,
-          ui::PointerDetails(ui::EventPointerType::kTouch, kPointerId));
-      view_->OnTouchEvent(&touch_event);
-
-      // Need to send a new press event after ending the previous touch.
-      if (use_exit_event)
-        sent_touch_press_ = false;
-    } else {
-      ui::EventPointerType pointer_type = ui::EventPointerType::kMouse;
-      if (GetEventParam() == TestEvent::kTouchEvent) {
-        DCHECK(Hovering(match_test_hovering_state));
-        pointer_type = ui::EventPointerType::kPen;
-      }
-
-      ui::EventType event_type = ui::ET_MOUSE_MOVED;
-      if (use_enter_event)
-        event_type = ui::ET_MOUSE_ENTERED;
-      if (use_exit_event)
-        event_type = ui::ET_MOUSE_EXITED;
-
-      int flags =
-          Hovering(match_test_hovering_state) ? 0 : ui::EF_LEFT_MOUSE_BUTTON;
-      ui::MouseEvent mouse_event(event_type, point, point, timestamp, flags, 0,
-                                 ui::PointerDetails(pointer_type, kPointerId));
-      view_->OnMouseEvent(&mouse_event);
-    }
-  }
-
-  MockCompositor* compositor() { return compositor_.get(); }
-
-  int32_t GetExpectedPointerId() const { return kPointerId; }
-
- private:
-  void SendTouchPress(const gfx::PointF& requested_touch_location) {
-    DCHECK(GetEventParam() == TestEvent::kTouchEvent);
-    if (sent_touch_press_)
-      return;
-
-    // Location of the press event doesn't matter, so long as it doesn't exactly
-    // match the location of the subsequent move event. If they match, then the
-    // move event is dropped.
-    gfx::PointF point(requested_touch_location.x() + 2.f,
-                      requested_touch_location.y() + 2.f);
-
-    ui::TouchEvent press(
-        ui::ET_TOUCH_PRESSED, point, point, ui::EventTimeForNow(),
-        ui::PointerDetails(ui::EventPointerType::kTouch, kPointerId));
-
-    view_->OnTouchEvent(&press);
-    sent_touch_press_ = true;
-  }
-
-  bool Hovering(bool match_test_hovering_state) {
-    return (GetHoverParam() == HoveringState::kHovering &&
-            match_test_hovering_state) ||
-           (GetHoverParam() == HoveringState::kNotHovering &&
-            !match_test_hovering_state);
-  }
-
-  // Pointer id to use in these tests. It must be consistent throughout a single
-  // test for some of the touch variations.
-  const int32_t kPointerId = 5;
-
-  // Touch events are ignored if a press isn't sent first, so use this to track
-  // if we have already sent a touch press event yet or not.
-  bool sent_touch_press_ = false;
-
-  // The real compositor that was contained by the |view_| and must be replaced
-  // before tear down, and the mock compositor used for getting the delegated
-  // ink points.
-  ui::Compositor* real_compositor_;
-  std::unique_ptr<MockCompositor> compositor_;
-};
-
-struct DelegatedInkPointTestPassToString {
-  std::string operator()(
-      const testing::TestParamInfo<std::tuple<TestEvent, HoveringState>> type)
-      const {
-    std::string suffix;
-
-    if (std::get<0>(type.param) == TestEvent::kMouseEvent)
-      suffix.append("Mouse");
-    else
-      suffix.append("Touch");
-
-    if (std::get<1>(type.param) == HoveringState::kHovering)
-      suffix.append("Hovering");
-    else
-      suffix.append("NotHovering");
-
-    return suffix;
-  }
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    DelegatedInkTrails,
-    DelegatedInkPointTest,
-    testing::Combine(
-        testing::Values(TestEvent::kMouseEvent, TestEvent::kTouchEvent),
-        testing::Values(HoveringState::kHovering, HoveringState::kNotHovering)),
-    DelegatedInkPointTestPassToString());
-
-// Tests to confirm that input events are correctly forwarded to the UI
-// Compositor when DelegatedInkTrails should be drawn, and stops forwarding when
-// they no longer should be drawn.
-TEST_P(DelegatedInkPointTest, EventForwardedToCompositor) {
-  // First confirm that the flag is false by default and the point is not sent.
-  SendEvent(true, gfx::PointF(15, 15));
-  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
-      compositor()->delegated_ink_point_renderer();
-
-  EXPECT_FALSE(delegated_ink_point_renderer);
-
-  // Then set it to true and confirm that the DelegatedInkPointRenderer is
-  // initialized, the connection is made and the point makes it to the renderer.
-  SetInkMetadataFlagOnRenderFrameMetadata(true);
-  gfx::DelegatedInkPoint expected_point(
-      gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId());
-  SendEvent(true, expected_point.point(), expected_point.timestamp());
-
-  delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer();
-  EXPECT_TRUE(delegated_ink_point_renderer);
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  gfx::DelegatedInkPoint actual_point =
-      delegated_ink_point_renderer->GetDelegatedInkPoint();
-  EXPECT_EQ(expected_point.point(), actual_point.point());
-  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
-  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
-
-  // Then try changing the scale factor to confirm it affects the point
-  // correctly.
-  const float scale = 2.6f;
-  aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(scale);
-  gfx::PointF unscaled_point(15, 15);
-  base::TimeTicks unscaled_time = base::TimeTicks::Now();
-
-  SendEvent(true, unscaled_point, unscaled_time);
-  delegated_ink_point_renderer->FlushForTesting();
-
-  unscaled_point.Scale(scale);
-  expected_point = gfx::DelegatedInkPoint(unscaled_point, unscaled_time,
-                                          GetExpectedPointerId());
-
-  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint();
-  EXPECT_EQ(expected_point.point(), actual_point.point());
-  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
-  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
-
-  // Confirm that prediction is reset when the API is no longer being used and
-  // |delegated_ink_metadata| is not set.
-  SetInkMetadataFlagOnRenderFrameMetadata(false);
-
-  SendEvent(true, gfx::PointF(25, 25));
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState());
-
-  // Finally, confirm that nothing is sent after the prediction has been reset
-  // when the delegated ink flag on the render frame metadata is false.
-  SendEvent(true, gfx::PointF(46, 46));
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState());
-}
-
-// Confirm that the interface is rebound if the receiver disconnects.
-TEST_P(DelegatedInkPointTest, MojoInterfaceReboundOnDisconnect) {
-  // First make sure the connection exists.
-  SetInkMetadataFlagOnRenderFrameMetadata(true);
-  SendEvent(true, gfx::PointF(15, 15));
-
-  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
-      compositor()->delegated_ink_point_renderer();
-
-  EXPECT_TRUE(delegated_ink_point_renderer);
-  EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound());
-
-  // Reset the receiver and flush the remote to confirm it is no longer bound.
-  delegated_ink_point_renderer->ResetReceiver();
-  view_->FlushForTest();
-
-  EXPECT_FALSE(delegated_ink_point_renderer->ReceiverIsBound());
-
-  // Confirm that it now gets reconnected correctly.
-  SendEvent(true, gfx::PointF(25, 25));
-
-  delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer();
-
-  EXPECT_TRUE(delegated_ink_point_renderer);
-  EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound());
-}
-
-// Test to confirm that forwarding points to viz will stop and prediction is
-// reset if the state of hovering differs between what is expected and the
-// received points.
-TEST_P(DelegatedInkPointTest, StopForwardingOnHoverStateChange) {
-  // First send a point and make sure it makes it to the renderer.
-  SetInkMetadataFlagOnRenderFrameMetadata(true);
-  SendEvent(true, gfx::PointF(15, 15));
-
-  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
-      compositor()->delegated_ink_point_renderer();
-  EXPECT_TRUE(delegated_ink_point_renderer);
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  delegated_ink_point_renderer->ClearDelegatedInkPoint();
-
-  // Now send a point that doesn't match the state of hovering on the metadata
-  // to confirm that it isn't sent and ResetPrediction is called.
-  SendEvent(false, gfx::PointF(20, 20));
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState());
-
-  // Send another that doesn't match to confirm the end trail point is only sent
-  // once.
-  SendEvent(false, gfx::PointF(25, 25));
-  delegated_ink_point_renderer->FlushForTesting();
-  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-
-  // Send one that does match again to confirm that points will start sending
-  // again if the hovering state starts matching again.
-  SendEvent(true, gfx::PointF(30, 30));
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState());
-}
-
-// Confirm that only move events are forwarded, not enter/exit or equivalent
-// events.
-TEST_P(DelegatedInkPointTest, IgnoreEnterAndExitEvents) {
-  // First set everything up and try forwarding a point, confirming that it is
-  // sent as expected.
-  SetInkMetadataFlagOnRenderFrameMetadata(true);
-  gfx::DelegatedInkPoint expected_point(
-      gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId());
-  SendEvent(true, expected_point.point(), expected_point.timestamp());
-
-  MockDelegatedInkPointRenderer* delegated_ink_point_renderer =
-      compositor()->delegated_ink_point_renderer();
-  EXPECT_TRUE(delegated_ink_point_renderer);
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  gfx::DelegatedInkPoint actual_point =
-      delegated_ink_point_renderer->GetDelegatedInkPoint();
-  EXPECT_EQ(expected_point.point(), actual_point.point());
-  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
-  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
-
-  // Try sending an enter event and confirm it is not forwarded.
-  SendEvent(true, gfx::PointF(12, 12), base::TimeTicks::Now(),
-            /*use_enter_event*/ true, /*use_exit_event*/ false);
-  delegated_ink_point_renderer->FlushForTesting();
-  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-
-  // Now try with an exit event.
-  SendEvent(true, gfx::PointF(42, 19), base::TimeTicks::Now(),
-            /*use_enter_event*/ false, /*use_exit_event*/ true);
-  delegated_ink_point_renderer->FlushForTesting();
-  EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-
-  // Finally, confirm that sending move events will work again without issue.
-  expected_point = gfx::DelegatedInkPoint(
-      gfx::PointF(20, 21), base::TimeTicks::Now(), GetExpectedPointerId());
-  SendEvent(true, expected_point.point(), expected_point.timestamp());
-
-  delegated_ink_point_renderer->FlushForTesting();
-
-  EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint());
-  actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint();
-  EXPECT_EQ(expected_point.point(), actual_point.point());
-  EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp());
-  EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id());
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index ec0d6b0..3e66a34e 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -988,4 +988,8 @@
       transformed_point);
 }
 
+ui::Compositor* RenderWidgetHostViewBase::GetCompositor() {
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 9e207025..6c9aa1e 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -54,6 +54,7 @@
 }
 
 namespace ui {
+class Compositor;
 enum class DomCode;
 class LatencyInfo;
 class TouchEvent;
@@ -544,6 +545,8 @@
 
   void SetTooltipObserverForTesting(TooltipObserver* observer);
 
+  virtual ui::Compositor* GetCompositor();
+
  protected:
   explicit RenderWidgetHostViewBase(RenderWidgetHost* host);
   ~RenderWidgetHostViewBase() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 14a83f94..4e26cd2ff 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -1003,4 +1003,10 @@
   host()->SynchronizeVisualProperties();
 }
 
+ui::Compositor* RenderWidgetHostViewChildFrame::GetCompositor() {
+  if (!GetRootView())
+    return nullptr;
+  return GetRootView()->GetCompositor();
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index a32e3e0..fdcd303 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -256,6 +256,8 @@
     return weak_factory_.GetWeakPtr();
   }
 
+  ui::Compositor* GetCompositor() override;
+
  protected:
   ~RenderWidgetHostViewChildFrame() override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index f4dbe7b3e..68ba083 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -364,69 +364,6 @@
   }
 }
 
-bool IsMoveEvent(ui::EventType type) {
-  return type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED ||
-         type == ui::ET_TOUCH_MOVED;
-}
-
-void RenderWidgetHostViewEventHandler::ForwardDelegatedInkPoint(
-    ui::LocatedEvent* event,
-    bool hovering,
-    int32_t pointer_id) {
-  const cc::RenderFrameMetadata& last_metadata =
-      host_->render_frame_metadata_provider()->LastRenderFrameMetadata();
-  if (IsMoveEvent(event->type()) &&
-      last_metadata.delegated_ink_metadata.has_value() &&
-      hovering == last_metadata.delegated_ink_metadata.value()
-                      .delegated_ink_is_hovering) {
-    if (!delegated_ink_point_renderer_.is_bound()) {
-      ui::Compositor* compositor = window_ && window_->layer()
-                                       ? window_->layer()->GetCompositor()
-                                       : nullptr;
-
-      // The remote can't be bound if the compositor is null, so bail if that
-      // is the case so we don't crash by trying to use an unbound remote.
-      if (!compositor)
-        return;
-
-      TRACE_EVENT_INSTANT0("input",
-                           "Binding mojo interface for delegated ink points.",
-                           TRACE_EVENT_SCOPE_THREAD);
-      compositor->SetDelegatedInkPointRenderer(
-          delegated_ink_point_renderer_.BindNewPipeAndPassReceiver());
-      delegated_ink_point_renderer_.reset_on_disconnect();
-    }
-
-    gfx::PointF point = event->root_location_f();
-    point.Scale(host_view_->GetDeviceScaleFactor());
-    gfx::DelegatedInkPoint delegated_ink_point(point, event->time_stamp(),
-                                               pointer_id);
-    TRACE_EVENT_INSTANT1("input",
-                         "Forwarding delegated ink point from browser.",
-                         TRACE_EVENT_SCOPE_THREAD, "delegated point",
-                         delegated_ink_point.ToString());
-
-    // Calling this will result in IPC calls to get |delegated_ink_point| to
-    // viz. The decision to do this here was made with the understanding that
-    // the IPC overhead will result in a minor increase in latency for getting
-    // this event to the renderer. However, by sending it here, the event is
-    // given the greatest possible chance to make it to viz before
-    // DrawAndSwap() is called, allowing more points to be drawn as part of
-    // the delegated ink trail, and thus reducing user perceived latency.
-    delegated_ink_point_renderer_->StoreDelegatedInkPoint(delegated_ink_point);
-    ended_delegated_ink_trail_ = false;
-  } else if (delegated_ink_point_renderer_.is_bound() &&
-             !ended_delegated_ink_trail_) {
-    // Let viz know that the most recent point it received from us is probably
-    // the last point the user is inking, so it shouldn't predict anything
-    // beyond it.
-    TRACE_EVENT_INSTANT0("input", "Delegated ink trail ended",
-                         TRACE_EVENT_SCOPE_THREAD);
-    delegated_ink_point_renderer_->ResetPrediction();
-    ended_delegated_ink_trail_ = true;
-  }
-}
-
 void RenderWidgetHostViewEventHandler::OnMouseEvent(ui::MouseEvent* event) {
   TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnMouseEvent");
 
@@ -470,9 +407,6 @@
     bool is_selection_popup = NeedsInputGrab(popup_child_host_view_);
     if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
         !(event->flags() & ui::EF_FROM_TOUCH)) {
-      bool hovering = (event->type() ^ ui::ET_MOUSE_DRAGGED) &&
-                      (event->type() ^ ui::ET_MOUSE_PRESSED);
-      ForwardDelegatedInkPoint(event, hovering, event->pointer_details().id);
 
       // Confirm existing composition text on mouse press, to make sure
       // the input caret won't be moved with an ongoing composition text.
@@ -597,9 +531,6 @@
   if (handled)
     return;
 
-  ForwardDelegatedInkPoint(event, event->hovering(),
-                           event->pointer_details().id);
-
   if (had_no_pointer)
     delegate_->selection_controller_client()->OnTouchDown();
   if (!pointer_state_.GetPointerCount())
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.h b/content/browser/renderer_host/render_widget_host_view_event_handler.h
index 65dbc6313..6d41f4d 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.h
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.h
@@ -12,14 +12,12 @@
 #include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/native_web_keyboard_event.h"
-#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/input/pointer_lock_result.mojom.h"
 #include "ui/aura/scoped_enable_unadjusted_mouse_events.h"
 #include "ui/aura/scoped_keyboard_hook.h"
 #include "ui/events/event_handler.h"
 #include "ui/events/gestures/motion_event_aura.h"
-#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
 #include "ui/latency/latency_info.h"
 
 namespace aura {
@@ -254,15 +252,6 @@
 
   void HandleMouseWheelEvent(ui::MouseEvent* event);
 
-  // Forward the location and timestamp of the event to viz if a delegated ink
-  // trail is requested.
-  void ForwardDelegatedInkPoint(ui::LocatedEvent* event,
-                                bool hovering,
-                                int32_t pointer_id);
-
-  // Flush the remote for testing purposes.
-  void FlushForTest() { delegated_ink_point_renderer_.FlushForTesting(); }
-
   // Whether return characters should be passed on to the RenderWidgetHostImpl.
   bool accept_return_character_ = false;
 
@@ -325,18 +314,6 @@
 
   std::unique_ptr<HitTestDebugKeyEventObserver> debug_observer_;
 
-  // Remote end of the connection for sending delegated ink points to viz to
-  // support the delegated ink trails feature.
-  mojo::Remote<gfx::mojom::DelegatedInkPointRenderer>
-      delegated_ink_point_renderer_;
-  // Used to know if we have already told viz to reset prediction because the
-  // final point of the delegated ink trail has been sent. True when prediction
-  // has already been reset for the most recent trail, false otherwise. This
-  // flag helps make sure that we don't send more IPCs than necessary to viz to
-  // reset prediction. Sending extra IPCs wouldn't impact correctness, but can
-  // impact performance due to the IPC overhead.
-  bool ended_delegated_ink_trail_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewEventHandler);
 };
 
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 05e9add2..556a1838 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
+#include "components/viz/common/features.h"
 #include "components/viz/test/host_frame_sink_manager_test_api.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/renderer_host/cursor_manager.h"
@@ -7328,4 +7329,130 @@
   EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
 }
 
+#if defined(USE_AURA)
+class SitePerProcessDelegatedInkBrowserTest
+    : public SitePerProcessHitTestBrowserTest {
+ public:
+  SitePerProcessDelegatedInkBrowserTest() = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    SitePerProcessHitTestBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
+                                    "DelegatedInkTrails");
+  }
+};
+
+// Test confirms that a point hitting an OOPIF that is requesting delegated ink
+// trails results in the metadata being correctly sent to the child's
+// RenderWidgetHost and is usable for sending delegated ink points.
+IN_PROC_BROWSER_TEST_F(SitePerProcessDelegatedInkBrowserTest,
+                       MetadataAndPointGoThroughOOPIF) {
+  // Delegated ink is only supported on Skia Renderer for now.
+  if (!features::IsUsingSkiaRenderer())
+    return;
+
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child = root->child_at(0);
+
+  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child->current_url());
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child->current_frame_host()->GetSiteInstance());
+
+  // Make sure the child frame is indeed a OOPIF
+  EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe());
+
+  EXPECT_TRUE(ExecJs(child->current_frame_host(), R"(
+      let presenter = null;
+      navigator.ink.requestPresenter('delegated-ink-trail').then(e => {
+        presenter = e;
+      });
+      let style = { color: 'green', diameter: 21 };
+
+      window.addEventListener('pointermove' , evt => {
+        presenter.updateInkTrailStartPoint(evt, style);
+        document.write('Force a new frame so that an updated ' +
+        'RenderFrameMetadata is sent to the browser process.');
+      });
+      )"));
+
+  RenderWidgetHostImpl* root_rwh =
+      root->current_frame_host()->GetRenderWidgetHost();
+  RenderWidgetHostImpl* child_rwh =
+      child->current_frame_host()->GetRenderWidgetHost();
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(root_rwh);
+  RenderWidgetHostMouseEventMonitor child_frame_monitor(child_rwh);
+
+  WaitForHitTestData(child->current_frame_host());
+
+  RenderWidgetHostViewBase* root_view =
+      static_cast<RenderWidgetHostViewBase*>(root_rwh->GetView());
+  RenderWidgetHostViewBase* rwhv_child =
+      static_cast<RenderWidgetHostViewBase*>(child_rwh->GetView());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  EXPECT_FALSE(router->IsDelegatedInkRendererBoundForTest());
+
+  // Target MouseMove to child frame.
+  blink::WebMouseEvent mouse_event(
+      blink::WebInputEvent::Type::kMouseMove,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  SetWebEventPositions(&mouse_event, gfx::Point(55, 55), root_view);
+
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &mouse_event);
+
+  // Dispatch twice because the router generates an extra MouseLeave for the
+  // main frame.
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &mouse_event);
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+
+  // Wait for the child to receive and process input so that the new
+  // RenderFrameMetadata is sent to the browser process.
+  {
+    auto observer = std::make_unique<MainThreadFrameObserver>(child_rwh);
+    observer->Wait();
+  }
+
+  // Confirm that the metadata is what we expect and accessible from the child's
+  // RenderWidgetHost.
+  const cc::RenderFrameMetadata& last_metadata =
+      child_rwh->render_frame_metadata_provider()->LastRenderFrameMetadata();
+  EXPECT_TRUE(last_metadata.delegated_ink_metadata.has_value());
+  EXPECT_TRUE(
+      last_metadata.delegated_ink_metadata.value().delegated_ink_is_hovering);
+
+  // Send one more mouse move event and confirm that it causes the forwarding
+  // to occur, which will result in the |delegated_ink_point_renderer_| mojom
+  // remote being bound.
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  SetWebEventPositions(&mouse_event, gfx::Point(57, 57), root_view);
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &mouse_event);
+
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(router->IsDelegatedInkRendererBoundForTest());
+}
+#endif  // USE_AURA
+
 }  // namespace content
diff --git a/content/test/data/accessibility/accname/name-text-dynamic-labelledby-expected-blink.txt b/content/test/data/accessibility/accname/name-text-dynamic-labelledby-expected-blink.txt
new file mode 100644
index 0000000..ac00307
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-dynamic-labelledby-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-dynamic-labelledby.html b/content/test/data/accessibility/accname/name-text-dynamic-labelledby.html
new file mode 100644
index 0000000..2b35939
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-dynamic-labelledby.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:description
+@WAIT-FOR:done
+-->
+<!DOCTYPE html>
+<html>
+<body>
+  <input id="test">
+  <div id="t1">foo</div>
+</body>
+</html>
+
+<script>
+  document.addEventListener('DOMContentLoaded', () => {
+    setTimeout(() => {
+      document.querySelector('#test').setAttribute("aria-labelledby", "t1");
+      document.title='done';
+    }, 50);
+  });
+</script>
diff --git a/content/test/data/accessibility/aria/aria-keyshortcuts-expected-mac.txt b/content/test/data/accessibility/aria/aria-keyshortcuts-expected-mac.txt
new file mode 100644
index 0000000..48d26aa0
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-keyshortcuts-expected-mac.txt
@@ -0,0 +1,5 @@
+AXWebArea
+++AXGroup
+++++AXButton AXKeyShortcutsValue='Ctrl+X' AXTitle='Cut'
+++++AXButton AXKeyShortcutsValue='Ctrl+C' AXTitle='Copy'
+++++AXButton AXKeyShortcutsValue='Ctrl+V' AXTitle='Paste'
diff --git a/content/test/data/accessibility/aria/aria-keyshortcuts.html b/content/test/data/accessibility/aria/aria-keyshortcuts.html
index 13526c5..60f4f1f 100644
--- a/content/test/data/accessibility/aria/aria-keyshortcuts.html
+++ b/content/test/data/accessibility/aria/aria-keyshortcuts.html
@@ -3,6 +3,7 @@
 @WIN-ALLOW:keyboard_shortcut=*
 @BLINK-ALLOW:keyShortcuts*
 @AURALINUX-ALLOW:keyshortcuts*
+@MAC-ALLOW:AXKeyShortcutsValue
 -->
 <html>
 <body>
diff --git a/content/test/data/accessibility/mac/textmarker/ax-next-word-end-text-marker-for-text-marker-expected-mac.txt b/content/test/data/accessibility/mac/textmarker/ax-next-word-end-text-marker-for-text-marker-expected-mac.txt
new file mode 100644
index 0000000..7ccfe4c
--- /dev/null
+++ b/content/test/data/accessibility/mac/textmarker/ax-next-word-end-text-marker-for-text-marker-expected-mac.txt
@@ -0,0 +1 @@
+textarea.AXNextWordEndTextMarkerForTextMarker({:3, 0, down})={:3, 3, down}
\ No newline at end of file
diff --git a/content/test/data/accessibility/mac/textmarker/ax-next-word-end-text-marker-for-text-marker.html b/content/test/data/accessibility/mac/textmarker/ax-next-word-end-text-marker-for-text-marker.html
new file mode 100644
index 0000000..736653f4
--- /dev/null
+++ b/content/test/data/accessibility/mac/textmarker/ax-next-word-end-text-marker-for-text-marker.html
@@ -0,0 +1,16 @@
+<!--
+@MAC-SCRIPT:
+  textarea.AXNextWordEndTextMarkerForTextMarker({:3, 0, down})
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+</style>
+</head>
+<body>
+<textarea id="textarea" style="font-family:monospace" rows="5" cols="15">
+The quick brown fox jumps over the lazy dog
+</textarea>
+</body>
+</html>
diff --git a/content/test/data/accessibility/mac/textmarker/ax-previous-word-start-text-marker-for-text-marker-expected-mac.txt b/content/test/data/accessibility/mac/textmarker/ax-previous-word-start-text-marker-for-text-marker-expected-mac.txt
new file mode 100644
index 0000000..61aac4f
--- /dev/null
+++ b/content/test/data/accessibility/mac/textmarker/ax-previous-word-start-text-marker-for-text-marker-expected-mac.txt
@@ -0,0 +1 @@
+textarea.AXPreviousWordStartTextMarkerForTextMarker({:3, 3, down})={:3, 0, down}
\ No newline at end of file
diff --git a/content/test/data/accessibility/mac/textmarker/ax-previous-word-start-text-marker-for-text-marker.html b/content/test/data/accessibility/mac/textmarker/ax-previous-word-start-text-marker-for-text-marker.html
new file mode 100644
index 0000000..fd22e41
--- /dev/null
+++ b/content/test/data/accessibility/mac/textmarker/ax-previous-word-start-text-marker-for-text-marker.html
@@ -0,0 +1,16 @@
+<!--
+@MAC-SCRIPT:
+  textarea.AXPreviousWordStartTextMarkerForTextMarker({:3, 3, down})
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+</style>
+</head>
+<body>
+<textarea id="textarea" style="font-family:monospace" rows="5" cols="15">
+The quick brown fox jumps over the lazy dog
+</textarea>
+</body>
+</html>
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index 88bd15d..cea0a32 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -234,6 +234,10 @@
   return display_feature_;
 }
 
+ui::Compositor* TestRenderWidgetHostView::GetCompositor() {
+  return compositor_;
+}
+
 TestRenderViewHost::TestRenderViewHost(
     FrameTree* frame_tree,
     SiteInstance* instance,
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index 5482020..0529c4ec 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -118,6 +118,7 @@
   viz::SurfaceId GetCurrentSurfaceId() const override;
   std::unique_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
       override;
+  ui::Compositor* GetCompositor() override;
 
   bool is_showing() const { return is_showing_; }
   bool is_occluded() const { return is_occluded_; }
@@ -129,6 +130,8 @@
 
   const WebCursor& last_cursor() const { return last_cursor_; }
 
+  void SetCompositor(ui::Compositor* compositor) { compositor_ = compositor; }
+
  protected:
   // RenderWidgetHostViewBase:
   void UpdateBackgroundColor() override;
@@ -154,6 +157,8 @@
 #endif
 
   absl::optional<DisplayFeature> display_feature_;
+
+  ui::Compositor* compositor_ = nullptr;
 };
 
 // TestRenderViewHost ----------------------------------------------------------
diff --git a/docs/speed/metrics_changelog/2020_11_lcp.md b/docs/speed/metrics_changelog/2020_11_lcp.md
index f4ce887..fb4aa6f 100644
--- a/docs/speed/metrics_changelog/2020_11_lcp.md
+++ b/docs/speed/metrics_changelog/2020_11_lcp.md
@@ -1,23 +1,18 @@
-# Largest Contentful Paint Changes in M88
+# Largest Contentful Paint Bug Fixes in M88
 
-## Changes in Chrome 88
+## Bug Fixes in Chrome 88
 
-In Chrome 88, some changes were made to Largest Contentful Paint to bring its
-implementation in line with the updated [specification](https://wicg.github.io/largest-contentful-paint/),
-and fix bugs in the chromium implementation.
+In Chrome 88, some bug fixes were made in the chromium implementation.
 
-The changes are:
+The bug fixes are:
 
  * Full viewport images, which are visually equivalent to background images, are
    no longer considered as the largest contentful paint.
    [Source code for this change](https://chromium-review.googlesource.com/c/chromium/src/+/2441732).
- * Images which are later removed from the page are now considered as potential
-   largest contentful paints.
-   [Source code for this change](https://chromium-review.googlesource.com/c/chromium/src/+/2480845).
  * Largest Contentful Paint stops recording after an input in an out of process
    iframe. This change only affects Chrome's reporting of Largest Contentful
    Paint in the [Chrome User Experience Report](https://developers.google.com/web/tools/chrome-user-experience-report),
-   as the API doesn't include iframes.
+   as the API doesn't report iframe content to the main frame.
    [Source code for this change](https://chromium-review.googlesource.com/c/chromium/src/+/2436770).
  * Prior to Chrome 88, Largest Contentful Paint had a bug where it incorrectly
    classified some images as invisible. This could happen in the case of
@@ -36,12 +31,6 @@
 content on the page is visible, and this generally is
 [not background images](https://github.com/anniesullie/LCP_Examples/blob/master/body_background/README.md).
 
-The change to include images which are later removed from the DOM as possible
-largest contentful paints will improve Largest Contentful Paint times on sites
-which have images of the same size inserted multiple times. This is a common
-pattern for carousels, as well as some JavaScript frameworks which do
-server-side rendering.
-
 The change to stop recording after an input in an out of process iframe will
 improve Largest Contentful Paint times on sites which have cross-process iframes.
 
diff --git a/docs/speed/metrics_changelog/2020_11_lcp_2.md b/docs/speed/metrics_changelog/2020_11_lcp_2.md
new file mode 100644
index 0000000..ba82ca5
--- /dev/null
+++ b/docs/speed/metrics_changelog/2020_11_lcp_2.md
@@ -0,0 +1,39 @@
+# Largest Contentful Paint Definition Change in M88
+
+## Definition Change in Chrome 88
+
+In Chrome 88, some changes were made to Largest Contentful Paint to bring its
+implementation in line with the updated [specification](https://wicg.github.io/largest-contentful-paint/).
+
+The definition change was the following: image or text content which is later
+removed from the page is now considered valid largest contentful paints.
+[Source code for this change](https://chromium-review.googlesource.com/c/chromium/src/+/2480845).
+
+Before this change, an element being removed caused it to no longer be
+considered a valid LCP candidate. In particular, if the current LCP candidate
+was removed from the site, this would immediately cause a new LCP candidate to
+be found among the content remaining on the page.
+
+After this change, an element being removed is still considered a valid LCP
+candidate. What this means is that if this candidate is removed then we do not
+need to immediately find a new LCP candidate. In particular, a new LCP candidate
+is only dispatched when a larger size is found, so the LCP entries should have
+size values that only increase over time.
+
+## How does this affect a site's metrics?
+
+The change to include content which is later removed from the DOM as possible
+largest contentful paints will improve Largest Contentful Paint times on sites
+which have images of the same size inserted multiple times. This is a common
+pattern for carousels, as well as some JavaScript frameworks which do
+server-side rendering.
+
+It's worth noting that while the change was made for the web API in Chrome 88,
+some tools which display real user metrics lagged behind this change, as we
+provided both LCP values (using the old definition and using the new one) to
+these tools while they make the necessary adjustments to swap to the new
+definition.
+
+## When were users affected?
+
+Chrome 88 is currently scheduled to be released the week of January 19, 2021.
diff --git a/docs/speed/metrics_changelog/lcp.md b/docs/speed/metrics_changelog/lcp.md
index 510e60e..58f7309 100644
--- a/docs/speed/metrics_changelog/lcp.md
+++ b/docs/speed/metrics_changelog/lcp.md
@@ -5,8 +5,8 @@
 * Chrome 88
   * Metric definition improvement: [Largest Contentful Paint ignores full viewport images](2020_11_lcp.md)
   * Metric definition improvement: [Largest Contentful Paint stops recording after input in an iframe](2020_11_lcp.md)
-  * Metric definition improvement: [Largest Contentful Paint ignores removed content by default](2020_11_lcp.md)
-  * Metric definition improvement: [Largest Contentful Paint bug fix for some images with source chagnes](2020_11_lcp.md)
+  * Metric definition improvement: [Largest Contentful Paint bug fix for some images with source changes](2020_11_lcp.md)
+  * Metric definition improvement: [Largest Contentful Paint ignores removed content by default](2020_11_lcp_2.md)
 * Chrome 86
   * Metric definition improvement: [Largest Contentful Paint ignores paints with opacity 0](2020_08_lcp.md)
 * Chrome 83
diff --git a/extensions/browser/api/device_permissions_manager.cc b/extensions/browser/api/device_permissions_manager.cc
index c42bbe4..37f38163 100644
--- a/extensions/browser/api/device_permissions_manager.cc
+++ b/extensions/browser/api/device_permissions_manager.cc
@@ -27,6 +27,7 @@
 #include "extensions/common/value_builder.h"
 #include "extensions/strings/grit/extensions_strings.h"
 #include "services/device/public/cpp/usb/usb_ids.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
@@ -111,14 +112,12 @@
       type != TypeToString(entry->type())) {
     return false;
   }
-  int vendor_id;
-  if (!value->GetIntegerWithoutPathExpansion(kDeviceVendorId, &vendor_id) ||
-      vendor_id != entry->vendor_id()) {
+  absl::optional<int> vendor_id = value->FindIntKey(kDeviceVendorId);
+  if (!vendor_id || vendor_id.value() != entry->vendor_id()) {
     return false;
   }
-  int product_id;
-  if (!value->GetIntegerWithoutPathExpansion(kDeviceProductId, &product_id) ||
-      product_id != entry->product_id()) {
+  absl::optional<int> product_id = value->FindIntKey(kDeviceProductId);
+  if (!product_id || product_id.value() != entry->product_id()) {
     return false;
   }
   std::u16string serial_number;
@@ -187,15 +186,14 @@
 
 scoped_refptr<DevicePermissionEntry> ReadDevicePermissionEntry(
     const base::DictionaryValue* entry) {
-  int vendor_id;
-  if (!entry->GetIntegerWithoutPathExpansion(kDeviceVendorId, &vendor_id) ||
-      vendor_id < 0 || vendor_id > UINT16_MAX) {
+  absl::optional<int> vendor_id = entry->FindIntKey(kDeviceVendorId);
+  if (!vendor_id || vendor_id.value() < 0 || vendor_id.value() > UINT16_MAX) {
     return nullptr;
   }
 
-  int product_id;
-  if (!entry->GetIntegerWithoutPathExpansion(kDeviceProductId, &product_id) ||
-      product_id < 0 || product_id > UINT16_MAX) {
+  absl::optional<int> product_id = entry->FindIntKey(kDeviceProductId);
+  if (!product_id || product_id.value() < 0 ||
+      product_id.value() > UINT16_MAX) {
     return nullptr;
   }
 
@@ -231,12 +229,12 @@
 
   if (type == kDeviceTypeUsb) {
     return base::MakeRefCounted<DevicePermissionEntry>(
-        DevicePermissionEntry::Type::USB, vendor_id, product_id, serial_number,
-        manufacturer_string, product_string, last_used);
+        DevicePermissionEntry::Type::USB, vendor_id.value(), product_id.value(),
+        serial_number, manufacturer_string, product_string, last_used);
   } else if (type == kDeviceTypeHid) {
     return base::MakeRefCounted<DevicePermissionEntry>(
-        DevicePermissionEntry::Type::HID, vendor_id, product_id, serial_number,
-        std::u16string(), product_string, last_used);
+        DevicePermissionEntry::Type::HID, vendor_id.value(), product_id.value(),
+        serial_number, std::u16string(), product_string, last_used);
   }
   return nullptr;
 }
diff --git a/extensions/browser/api/socket/tcp_socket.cc b/extensions/browser/api/socket/tcp_socket.cc
index 0ae69cf..217be3e 100644
--- a/extensions/browser/api/socket/tcp_socket.cc
+++ b/extensions/browser/api/socket/tcp_socket.cc
@@ -85,8 +85,7 @@
     : Socket(owner_extension_id),
       browser_context_(browser_context),
       socket_mode_(UNKNOWN),
-      mojo_data_pump_(nullptr),
-      task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
+      mojo_data_pump_(nullptr) {}
 
 TCPSocket::TCPSocket(
     mojo::PendingRemote<network::mojom::TCPConnectedSocket> socket,
@@ -100,7 +99,6 @@
       client_socket_(std::move(socket)),
       mojo_data_pump_(std::make_unique<MojoDataPump>(std::move(receive_stream),
                                                      std::move(send_stream))),
-      task_runner_(base::SequencedTaskRunnerHandle::Get()),
       peer_addr_(remote_addr) {
   is_connected_ = true;
 }
@@ -111,6 +109,7 @@
 
 void TCPSocket::Connect(const net::AddressList& address,
                         net::CompletionOnceCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(callback);
 
   if (socket_mode_ == SERVER || connect_callback_) {
@@ -127,22 +126,19 @@
   socket_mode_ = CLIENT;
   connect_callback_ = std::move(callback);
 
-  // |completion_callback| is called on current thread.
   network::mojom::NetworkContext::CreateTCPConnectedSocketCallback
       completion_callback = base::BindOnce(&TCPSocket::OnConnectComplete,
                                            weak_factory_.GetWeakPtr());
 
-  // |completion_callback_ui| is called on the UI thread.
-  network::mojom::NetworkContext::CreateTCPConnectedSocketCallback
-      completion_callback_ui =
-          base::BindOnce(&TCPSocket::OnConnectCompleteOnUIThread, task_runner_,
-                         std::move(completion_callback));
-
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&TCPSocket::ConnectOnUIThread,
-                                storage_partition_, browser_context_, address,
-                                client_socket_.BindNewPipeAndPassReceiver(),
-                                std::move(completion_callback_ui)));
+  if (!storage_partition_) {
+    storage_partition_ = browser_context_->GetDefaultStoragePartition();
+  }
+  storage_partition_->GetNetworkContext()->CreateTCPConnectedSocket(
+      absl::nullopt, address, /*options=*/nullptr,
+      net::MutableNetworkTrafficAnnotationTag(
+          Socket::GetNetworkTrafficAnnotationTag()),
+      client_socket_.BindNewPipeAndPassReceiver(),
+      /*oberserver=*/mojo::NullRemote(), std::move(completion_callback));
 }
 
 void TCPSocket::Disconnect(bool socket_destroying) {
@@ -231,6 +227,7 @@
                        uint16_t port,
                        int backlog,
                        ListenCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!server_socket_);
   DCHECK(!client_socket_);
   DCHECK(!listen_callback_);
@@ -256,18 +253,15 @@
       completion_callback = base::BindOnce(&TCPSocket::OnListenComplete,
                                            weak_factory_.GetWeakPtr());
 
-  // |completion_callback_ui| is called on the UI thread.
-  network::mojom::NetworkContext::CreateTCPServerSocketCallback
-      completion_callback_ui =
-          base::BindOnce(&TCPSocket::OnListenCompleteOnUIThread, task_runner_,
-                         std::move(completion_callback));
-
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(&TCPSocket::ListenOnUIThread, storage_partition_,
-                     browser_context_, ip_end_point, backlog,
-                     server_socket_.BindNewPipeAndPassReceiver(),
-                     std::move(completion_callback_ui)));
+  if (!storage_partition_) {
+    storage_partition_ = browser_context_->GetDefaultStoragePartition();
+  }
+  storage_partition_->GetNetworkContext()->CreateTCPServerSocket(
+      ip_end_point, backlog,
+      net::MutableNetworkTrafficAnnotationTag(
+          Socket::GetNetworkTrafficAnnotationTag()),
+      server_socket_.BindNewPipeAndPassReceiver(),
+      std::move(completion_callback));
 }
 
 void TCPSocket::Accept(AcceptCompletionCallback callback) {
@@ -325,53 +319,15 @@
   return net::ERR_IO_PENDING;
 }
 
-// static
-void TCPSocket::ConnectOnUIThread(
-    content::StoragePartition* storage_partition,
-    content::BrowserContext* browser_context,
-    const net::AddressList& remote_addr_list,
-    mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
-    network::mojom::NetworkContext::CreateTCPConnectedSocketCallback
-        completion_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  if (!storage_partition) {
-    storage_partition = browser_context->GetDefaultStoragePartition();
-  }
-  storage_partition->GetNetworkContext()->CreateTCPConnectedSocket(
-      absl::nullopt, remote_addr_list, nullptr /* options */,
-      net::MutableNetworkTrafficAnnotationTag(
-          Socket::GetNetworkTrafficAnnotationTag()),
-      std::move(receiver), mojo::NullRemote() /* observer */,
-      std::move(completion_callback));
-}
-
-// static
-void TCPSocket::OnConnectCompleteOnUIThread(
-    scoped_refptr<base::SequencedTaskRunner> original_task_runner,
-    network::mojom::NetworkContext::CreateTCPConnectedSocketCallback callback,
-    int result,
-    const absl::optional<net::IPEndPoint>& local_addr,
-    const absl::optional<net::IPEndPoint>& peer_addr,
-    mojo::ScopedDataPipeConsumerHandle receive_stream,
-    mojo::ScopedDataPipeProducerHandle send_stream) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  original_task_runner->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), result, local_addr, peer_addr,
-                     std::move(receive_stream), std::move(send_stream)));
-}
-
 void TCPSocket::OnConnectComplete(
     int result,
     const absl::optional<net::IPEndPoint>& local_addr,
     const absl::optional<net::IPEndPoint>& peer_addr,
     mojo::ScopedDataPipeConsumerHandle receive_stream,
     mojo::ScopedDataPipeProducerHandle send_stream) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!is_connected_);
   DCHECK(connect_callback_);
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   if (result == net::OK) {
     is_connected_ = true;
@@ -383,42 +339,10 @@
   std::move(connect_callback_).Run(result);
 }
 
-// static
-void TCPSocket::ListenOnUIThread(
-    content::StoragePartition* storage_partition,
-    content::BrowserContext* browser_context,
-    const net::IPEndPoint& local_addr,
-    int backlog,
-    mojo::PendingReceiver<network::mojom::TCPServerSocket> receiver,
-    network::mojom::NetworkContext::CreateTCPServerSocketCallback callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  if (!storage_partition) {
-    storage_partition = browser_context->GetDefaultStoragePartition();
-  }
-  storage_partition->GetNetworkContext()->CreateTCPServerSocket(
-      local_addr, backlog,
-      net::MutableNetworkTrafficAnnotationTag(
-          Socket::GetNetworkTrafficAnnotationTag()),
-      std::move(receiver), std::move(callback));
-}
-
-// static
-void TCPSocket::OnListenCompleteOnUIThread(
-    const scoped_refptr<base::SequencedTaskRunner>& original_task_runner,
-    network::mojom::NetworkContext::CreateTCPServerSocketCallback callback,
-    int result,
-    const absl::optional<net::IPEndPoint>& local_addr) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  original_task_runner->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), result, local_addr));
-}
-
 void TCPSocket::OnListenComplete(
     int result,
     const absl::optional<net::IPEndPoint>& local_addr) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(listen_callback_);
 
   if (result != net::OK) {
diff --git a/extensions/browser/api/socket/tcp_socket.h b/extensions/browser/api/socket/tcp_socket.h
index c34f2b1..ae18fcf 100644
--- a/extensions/browser/api/socket/tcp_socket.h
+++ b/extensions/browser/api/socket/tcp_socket.h
@@ -98,45 +98,14 @@
                 net::CompletionOnceCallback callback) override;
 
  private:
-  // Connects a client TCP socket. This is done on the UI thread because
-  // StoragePartition::GetNetworkContext() needs to happen on the UI thread.
-  // The completion callback is posted back to the thread on which |this| lives.
-  static void ConnectOnUIThread(
-      content::StoragePartition* storage_partition,
-      content::BrowserContext* browser_context,
-      const net::AddressList& remote_address_list,
-      mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
-      network::mojom::NetworkContext::CreateTCPConnectedSocketCallback
-          callback);
-  static void OnConnectCompleteOnUIThread(
-      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
-      network::mojom::NetworkContext::CreateTCPConnectedSocketCallback callback,
-      int result,
-      const absl::optional<net::IPEndPoint>& local_addr,
-      const absl::optional<net::IPEndPoint>& peer_addr,
-      mojo::ScopedDataPipeConsumerHandle receive_stream,
-      mojo::ScopedDataPipeProducerHandle send_stream);
+  // Connects a client TCP socket.
   void OnConnectComplete(int result,
                          const absl::optional<net::IPEndPoint>& local_addr,
                          const absl::optional<net::IPEndPoint>& peer_addr,
                          mojo::ScopedDataPipeConsumerHandle receive_stream,
                          mojo::ScopedDataPipeProducerHandle send_stream);
 
-  // Connects a server TCP socket. This is done on the UI thread because
-  // StoragePartition::GetNetworkContext() needs to happen on the UI thread.
-  // The completion callback is posted back to the thread on which |this| lives.
-  static void ListenOnUIThread(
-      content::StoragePartition* storage_partition,
-      content::BrowserContext* browser_context,
-      const net::IPEndPoint& local_addr,
-      int backlog,
-      mojo::PendingReceiver<network::mojom::TCPServerSocket> receiver,
-      network::mojom::NetworkContext::CreateTCPServerSocketCallback callback);
-  static void OnListenCompleteOnUIThread(
-      const scoped_refptr<base::SequencedTaskRunner>& original_task_runner,
-      network::mojom::NetworkContext::CreateTCPServerSocketCallback callback,
-      int result,
-      const absl::optional<net::IPEndPoint>& local_addr);
+  // Connects a server TCP socket.
   void OnListenComplete(int result,
                         const absl::optional<net::IPEndPoint>& local_addr);
   void OnAccept(
@@ -183,8 +152,6 @@
 
   std::unique_ptr<MojoDataPump> mojo_data_pump_;
 
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
   absl::optional<net::IPEndPoint> local_addr_;
   absl::optional<net::IPEndPoint> peer_addr_;
 
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
index ecc4a110..0cdb37a0 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -205,8 +205,8 @@
 // potential race between the cross-origin renderer initiated navigation and
 // the navigation to "about:blank" started from the browser.
 //
-// Disabled on Linux due to flakiness: https://crbug.com/1182355.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+// Disabled on Linux and Mac due to flakiness: https://crbug.com/1182355.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_MAC)
 #define MAYBE_NavigationRaceFromEmbedder DISABLED_NavigationRaceFromEmbedder
 #else
 #define MAYBE_NavigationRaceFromEmbedder NavigationRaceFromEmbedder
diff --git a/fuchsia/cipd/BUILD.gn b/fuchsia/cipd/BUILD.gn
index ecb41b0..f69803b 100644
--- a/fuchsia/cipd/BUILD.gn
+++ b/fuchsia/cipd/BUILD.gn
@@ -7,6 +7,7 @@
 assert(is_fuchsia)
 
 import("//build/cipd/cipd.gni")
+import("//build/config/chrome_build.gni")
 import("//build/util/process_version.gni")
 import("//third_party/fuchsia-sdk/sdk/build/build_id_dir.gni")
 import("//third_party/fuchsia-sdk/sdk/build/cipd.gni")
@@ -18,6 +19,12 @@
   _gn_path = "//buildtools/linux64/gn"
 }
 
+if (is_chrome_branded) {
+  package_base_path = "chrome_internal/fuchsia"
+} else {
+  package_base_path = "chromium/fuchsia"
+}
+
 # Extracts the numeric Chrome build ID and writes it to a file in the output
 # directory.
 #
@@ -108,29 +115,7 @@
       package_relative_path = "${package_basename}-$targetarch"
     }
 
-    package = "chromium/fuchsia/${package_relative_path}"
-
-    if (!defined(package_definition_name)) {
-      package_definition_name = "${target_name}.yaml"
-    }
-
-    # Always use absolute path.
-    use_absolute_root_path = true
-  }
-
-  # TODO (crbug.com/1169400): Remove this target when Fuchsia side is ready to
-  # transition.
-  fuchsia_cipd_package("${target_name}_google") {
-    if (!defined(package_relative_path)) {
-      if (target_cpu == "x64") {
-        targetarch = "amd64"
-      } else {
-        targetarch = "arm64"
-      }
-      package_relative_path = "${package_basename}-$targetarch"
-    }
-
-    package = "chrome_internal/fuchsia/${package_relative_path}"
+    package = "${package_base_path}/${package_relative_path}"
 
     if (!defined(package_definition_name)) {
       package_definition_name = "${target_name}.yaml"
@@ -297,7 +282,7 @@
 
 fuchsia_cipd_package(_debug_symbols_archive_name) {
   testonly = true
-  package = "chromium/fuchsia/debug-symbols-${targetarch}"
+  package = "${package_base_path}/debug-symbols-${targetarch}"
   package_root = _debug_symbols_outdir
   package_definition_name = "${target_name}.yaml"
   package_definition_dir = "${target_gen_dir}/${target_name}"
@@ -308,19 +293,6 @@
   deps = [ ":${_build_ids_target}" ]
 }
 
-fuchsia_cipd_package("${_debug_symbols_archive_name}_google") {
-  testonly = true
-  package = "chrome_internal/fuchsia/debug-symbols-${targetarch}"
-  package_root = _debug_symbols_outdir
-  package_definition_name = "${target_name}.yaml"
-  package_definition_dir = "${target_gen_dir}/${_debug_symbols_archive_name}"
-  description = "Debugging symbols for prebuilt binaries from Chromium."
-  use_absolute_root_path = true
-
-  directories = [ "." ]
-  deps = [ ":${_build_ids_target}" ]
-}
-
 cipd_archive("clear_key_cdm") {
   package_basename = "libclearkeycdm"
   description = "Prebuilt libclearkeycdm.so binary for Fuchsia."
@@ -337,20 +309,12 @@
   testonly = true
   deps = [
     ":castrunner",
-    ":castrunner_google",
     ":chromedriver",
-    ":chromedriver_google",
     ":clear_key_cdm",
-    ":clear_key_cdm_google",
     ":debug_symbols",
-    ":debug_symbols_google",
     ":http",
-    ":http_google",
     ":tests",
-    ":tests_google",
     ":web_engine_shell",
-    ":web_engine_shell_google",
     ":webrunner",
-    ":webrunner_google",
   ]
 }
diff --git a/fuchsia/engine/context_provider_main.cc b/fuchsia/engine/context_provider_main.cc
index 0168ba84..37202d89 100644
--- a/fuchsia/engine/context_provider_main.cc
+++ b/fuchsia/engine/context_provider_main.cc
@@ -24,6 +24,7 @@
 
 namespace {
 
+// This must match the value in web_instance_host.cc
 constexpr char kCrashProductName[] = "FuchsiaWebEngine";
 // TODO(https://fxbug.dev/51490): Use a programmatic mechanism to obtain this.
 constexpr char kComponentUrl[] =
diff --git a/fuchsia/engine/web_instance_host/web_instance_host.cc b/fuchsia/engine/web_instance_host/web_instance_host.cc
index 8d68ff7..d59eeef8 100644
--- a/fuchsia/engine/web_instance_host/web_instance_host.cc
+++ b/fuchsia/engine/web_instance_host/web_instance_host.cc
@@ -89,14 +89,11 @@
 // is available - see crbug.com/1211174). This should only be called once per
 // process, and the calling thread must have an async_dispatcher.
 void RegisterWebInstanceProductData() {
-  // TODO(fxbug.dev/51490): Use a programmatic mechanism to obtain this.
-  constexpr char kComponentUrl[] =
-      "fuchsia-pkg://fuchsia.com/web_engine#meta/web_instance.cmx";
   constexpr char kCrashProductName[] = "FuchsiaWebEngine";
   constexpr char kFeedbackAnnotationsNamespace[] = "web-engine";
 
-  cr_fuchsia::RegisterProductDataForCrashReporting(kComponentUrl,
-                                                   kCrashProductName);
+  cr_fuchsia::RegisterProductDataForCrashReporting(
+      WebInstanceHost::kComponentUrl, kCrashProductName);
 
   cr_fuchsia::RegisterProductDataForFeedback(kFeedbackAnnotationsNamespace);
 }
@@ -405,6 +402,7 @@
 }  // namespace
 
 // Production URL for web hosting Component instances.
+// TODO(fxbug.dev/51490): Use a programmatic mechanism to obtain this.
 const char WebInstanceHost::kComponentUrl[] =
     "fuchsia-pkg://fuchsia.com/web_engine#meta/web_instance.cmx";
 
diff --git a/fuchsia/engine/web_instance_host/web_instance_host.h b/fuchsia/engine/web_instance_host/web_instance_host.h
index b75cacc..c2b6bcb 100644
--- a/fuchsia/engine/web_instance_host/web_instance_host.h
+++ b/fuchsia/engine/web_instance_host/web_instance_host.h
@@ -21,6 +21,8 @@
 // 1. Include the "web_instance.cmx" in their package, for the implementation
 //    to read the sandbox services from.
 // 2. List the fuchsia.sys.Environment & .Loader services in their sandbox.
+// 3. Have web_engine's config-data available to the calling Component.
+//    TODO(crbug.com/1212191): Make web_instance read the config & remove this.
 //
 // To ensure proper product data registration, Components using the class must:
 // * Have the same version and channel as WebEngine.
diff --git a/fuchsia/release/size_tests/fyi_sizes_warning.json b/fuchsia/release/size_tests/fyi_sizes_warning.json
index 443a057..9934e32 100644
--- a/fuchsia/release/size_tests/fyi_sizes_warning.json
+++ b/fuchsia/release/size_tests/fyi_sizes_warning.json
@@ -5,6 +5,6 @@
   ],
   "far_total_name" : "chrome_fuchsia",
   "size_limits" : {
-    "chrome_fuchsia_compressed": 38.6e6
+    "chrome_fuchsia_compressed": 39845888
   }
 }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 21ea9fc..391a66f 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -36,6 +36,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace {
 
@@ -60,10 +61,10 @@
   std::string refresh_token;
   std::string access_token;
   std::string id_token;
-  int expires_in_secs;
+  absl::optional<int> expires_in_secs = dict->FindIntKey("expires_in");
   if (!dict->GetStringWithoutPathExpansion("refresh_token", &refresh_token) ||
       !dict->GetStringWithoutPathExpansion("access_token", &access_token) ||
-      !dict->GetIntegerWithoutPathExpansion("expires_in", &expires_in_secs)) {
+      !expires_in_secs.has_value()) {
     return nullptr;
   }
 
@@ -75,7 +76,7 @@
   gaia::TokenServiceFlags service_flags = gaia::ParseServiceFlags(id_token);
 
   return std::make_unique<const GaiaAuthConsumer::ClientOAuthResult>(
-      refresh_token, access_token, expires_in_secs,
+      refresh_token, access_token, expires_in_secs.value(),
       service_flags.is_child_account,
       service_flags.is_under_advanced_protection);
 }
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 5c56253..5ec629fd 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -8590,7 +8590,7 @@
         properties_j: "$recipe_engine/resultdb/test_presentation:{\"column_keys\":[],\"grouping_keys\":[\"status\",\"v.test_suite\"]}"
         properties_j: "builder_group:\"chromium.memory\""
       }
-      execution_timeout_secs: 14400
+      execution_timeout_secs: 18000
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index 8f29d1d..93658b5c1 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -5787,7 +5787,7 @@
     ),
     cores = 32,
     # TODO(thakis): Remove once https://crbug.com/927738 is resolved.
-    execution_timeout = 4 * time.hour,
+    execution_timeout = 5 * time.hour,
     goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
     main_console_view = "main",
 )
diff --git a/ios/chrome/app/application_delegate/app_state.h b/ios/chrome/app/application_delegate/app_state.h
index 459a810..5357b168 100644
--- a/ios/chrome/app/application_delegate/app_state.h
+++ b/ios/chrome/app/application_delegate/app_state.h
@@ -161,6 +161,9 @@
 
 // Adds an observer to this app state. The observers will be notified about
 // app state changes per AppStateObserver protocol.
+// The observer will be *immediately* notified about the latest init stage
+// transition, if any such transitions happened (didTransitionFromInitStage),
+// before this method returns.
 - (void)addObserver:(id<AppStateObserver>)observer;
 // Removes the observer. It's safe to call this at any time, including from
 // AppStateObserver callbacks.
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index 3512b55..6007ae1 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -222,6 +222,15 @@
 - (void)setInitStage:(InitStage)newInitStage {
   DCHECK(newInitStage >= InitStageStart);
   DCHECK(newInitStage <= InitStageFinal);
+  // As of writing this, it seems reasonable for init stages to be strictly
+  // incremented by one only: if a stage needs to be skipped, it can just be a
+  // no-op, but the observers will get a chance to react to it normally. If in
+  // the future these need to be skipped, or go backwards:
+  // 1. Check that all observers will support this change
+  // 2. Keep the previous init stage and modify addObserver: code to send the
+  // previous init stage instead.
+  DCHECK(newInitStage == _initStage + 1 ||
+         (newInitStage == InitStageStart && _initStage == InitStageStart));
   // It's probably a programming error to set the same init stage twice, except
   // for InitStageStart to kick off the startup.
   DCHECK(newInitStage == InitStageStart || _initStage != newInitStage);
@@ -529,8 +538,16 @@
   self.shouldPerformAdditionalDelegateHandling = !URLHandled;
 }
 
-- (void)addObserver:(id<SceneStateObserver>)observer {
+- (void)addObserver:(id<AppStateObserver>)observer {
   [self.observers addObserver:observer];
+
+  if ([observer respondsToSelector:@selector(appState:
+                                       didTransitionFromInitStage:)] &&
+      self.initStage > InitStageStart) {
+    InitStage previousInitStage = static_cast<InitStage>(self.initStage - 1);
+    // Trigger an update on the newly added agent.
+    [observer appState:self didTransitionFromInitStage:previousInitStage];
+  }
 }
 
 - (void)removeObserver:(id<SceneStateObserver>)observer {
diff --git a/ios/chrome/app/safe_mode_app_state_agent_unittest.mm b/ios/chrome/app/safe_mode_app_state_agent_unittest.mm
index 60aa5f5..99d038c1 100644
--- a/ios/chrome/app/safe_mode_app_state_agent_unittest.mm
+++ b/ios/chrome/app/safe_mode_app_state_agent_unittest.mm
@@ -143,17 +143,13 @@
   [[windowMock stub] setRootViewController:[OCMArg any]];
 
   AppState* appState = getAppStateWithMock();
-  id appStateMock = OCMPartialMock(appState);
-  [[appStateMock expect] queueTransitionToNextInitStage];
-  [[appStateMock expect] appState:appState
-       didTransitionFromInitStage:InitStageSafeMode];
 
   swizzleSafeModeShouldStart(YES);
 
   SafeModeAppAgent* agent = [[SafeModeAppAgent alloc] init];
-  [agent setAppState:appStateMock];
+  [agent setAppState:appState];
 
-  IterateToStage(InitStageStart, InitStageSafeMode, agent, appStateMock);
+  IterateToStage(InitStageStart, InitStageSafeMode, agent, appState);
 
   SceneState* sceneState = GetSceneState();
 
@@ -168,9 +164,6 @@
   // Exit safe mode.
   [agent coordinatorDidExitSafeMode:agent.safeModeCoordinator];
 
-  IterateToStage(InitStageFinal, InitStageFinal, agent, appStateMock);
-
-  EXPECT_OCMOCK_VERIFY(appStateMock);
   EXPECT_EQ(nil, agent.safeModeCoordinator);
 }
 
diff --git a/ios/chrome/app/strings/resources/ios_strings_bn.xtb b/ios/chrome/app/strings/resources/ios_strings_bn.xtb
index c75bb96..6725d43 100644
--- a/ios/chrome/app/strings/resources/ios_strings_bn.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_bn.xtb
@@ -493,6 +493,7 @@
 <translation id="6059830886158432458">আপনার খবর ও গতিবিধি এখানে নিয়ন্ত্রণ করুন</translation>
 <translation id="6066301408025741299">বাতিল করতে আলতো চাপুন৷</translation>
 <translation id="60829778314739003">সম্মতি দিন এবং কাজ চালিয়ে যান</translation>
+<translation id="6084848228346514841">ট্যাব বেছে নিন</translation>
 <translation id="6108923351542677676">সেটআপ চলছে...</translation>
 <translation id="6119050551270742952">বর্তমান ওয়েবপেজটি ছদ্মবেশী মোডে আছে</translation>
 <translation id="6122191549521593678">অনলাইন</translation>
@@ -783,6 +784,7 @@
 <ph name="BEGIN_LINK" />আরও জানুন<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">Bookmarks</translation>
 <translation id="8840513115188359703">আপনাকে Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না।</translation>
+<translation id="8868471676553493380">{count,plural, =1{{count}টি ট্যাব}one{{count}টি ট্যাব}other{{count}টি ট্যাব}}</translation>
 <translation id="8870413625673593573">সম্প্রতি বন্ধ হয়েছে</translation>
 <translation id="8876882697946675716">আপনার ডিভাইস সিঙ্ক করে রাখুন</translation>
 <translation id="8881801611828450202">এই ইমেজটির জন্য <ph name="SEARCH_ENGINE" />-এ খুঁজুন</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
index 320e6ee..8e116d0 100644
--- a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
@@ -198,7 +198,7 @@
 <translation id="2964349545761222050">Block third-party cookies</translation>
 <translation id="2969979262385602596">Failed to sign in. Please try again later.</translation>
 <translation id="2975121486251958312">Only Incognito mode is available</translation>
-<translation id="2982481275546140226">Clear Data</translation>
+<translation id="2982481275546140226">Clear data</translation>
 <translation id="298306318844797842">Add Payment Method...</translation>
 <translation id="2989805286512600854">Open in New Tab</translation>
 <translation id="3037605927509011580">Aw, Snap!</translation>
diff --git a/ios/chrome/browser/sync/ios_trusted_vault_client.h b/ios/chrome/browser/sync/ios_trusted_vault_client.h
index e85ed7b..9c49180 100644
--- a/ios/chrome/browser/sync/ios_trusted_vault_client.h
+++ b/ios/chrome/browser/sync/ios_trusted_vault_client.h
@@ -24,6 +24,7 @@
   void StoreKeys(const std::string& gaia_id,
                  const std::vector<std::vector<uint8_t>>& keys,
                  int last_key_version) override;
+  void RemoveAllStoredKeys() override;
   void MarkKeysAsStale(const CoreAccountInfo& account_info,
                        base::OnceCallback<void(bool)> callback) override;
   void GetIsRecoverabilityDegraded(
diff --git a/ios/chrome/browser/sync/ios_trusted_vault_client.mm b/ios/chrome/browser/sync/ios_trusted_vault_client.mm
index 679a06d..23e0c3b 100644
--- a/ios/chrome/browser/sync/ios_trusted_vault_client.mm
+++ b/ios/chrome/browser/sync/ios_trusted_vault_client.mm
@@ -61,6 +61,11 @@
   NOTREACHED();
 }
 
+void IOSTrustedVaultClient::RemoveAllStoredKeys() {
+  // Not used on iOS.
+  NOTREACHED();
+}
+
 void IOSTrustedVaultClient::MarkKeysAsStale(
     const CoreAccountInfo& account_info,
     base::OnceCallback<void(bool)> callback) {
diff --git a/ios/chrome/browser/ui/thumb_strip/thumb_strip_coordinator.mm b/ios/chrome/browser/ui/thumb_strip/thumb_strip_coordinator.mm
index d9565a1..ce62e7d 100644
--- a/ios/chrome/browser/ui/thumb_strip/thumb_strip_coordinator.mm
+++ b/ios/chrome/browser/ui/thumb_strip/thumb_strip_coordinator.mm
@@ -117,6 +117,12 @@
   }
   self.mediator.incognitoWebStateList =
       _incognitoBrowser ? _incognitoBrowser->GetWebStateList() : nullptr;
+
+  self.mediator.incognitoOverlayPresentationContext =
+      _incognitoBrowser
+          ? OverlayPresentationContext::FromBrowser(
+                _incognitoBrowser, OverlayModality::kInfobarBanner)
+          : nullptr;
 }
 
 #pragma mark - ThumbStripNavigationConsumer
diff --git a/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm b/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm
index e51896e3..c38be7fe 100644
--- a/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm
+++ b/ios/chrome/browser/ui/thumb_strip/thumb_strip_mediator.mm
@@ -156,7 +156,9 @@
                                toState:(ViewRevealState)nextViewRevealState {
   if (nextViewRevealState == ViewRevealState::Revealed) {
     self.regularOverlayPresentationContext->SetUIDisabled(true);
-    self.incognitoOverlayPresentationContext->SetUIDisabled(true);
+    if (self.incognitoOverlayPresentationContext) {
+      self.incognitoOverlayPresentationContext->SetUIDisabled(true);
+    }
   }
 }
 
@@ -168,7 +170,9 @@
   if (viewRevealState == ViewRevealState::Peeked ||
       viewRevealState == ViewRevealState::Hidden) {
     self.regularOverlayPresentationContext->SetUIDisabled(false);
-    self.incognitoOverlayPresentationContext->SetUIDisabled(false);
+    if (self.incognitoOverlayPresentationContext) {
+      self.incognitoOverlayPresentationContext->SetUIDisabled(false);
+    }
   }
 }
 
diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui.mm b/ios/chrome/browser/ui/webui/policy/policy_ui.mm
index c814a6b3..71230a1 100644
--- a/ios/chrome/browser/ui/webui/policy/policy_ui.mm
+++ b/ios/chrome/browser/ui/webui/policy/policy_ui.mm
@@ -63,6 +63,7 @@
       {"offHoursNotActive", IDS_POLICY_OFFHOURS_NOT_ACTIVE},
       {"policiesPushOff", IDS_POLICY_PUSH_POLICIES_OFF},
       {"policiesPushOn", IDS_POLICY_PUSH_POLICIES_ON},
+      {"policyCopyValue", IDS_POLICY_COPY_VALUE},
       {"policyLearnMore", IDS_POLICY_LEARN_MORE},
       {"reloadPolicies", IDS_POLICY_RELOAD_POLICIES},
       {"showExpandedStatus", IDS_POLICY_SHOW_EXPANDED_STATUS},
diff --git a/ios/web/net/cookies/crw_wk_http_cookie_store.mm b/ios/web/net/cookies/crw_wk_http_cookie_store.mm
index bba32d1..65d0347 100644
--- a/ios/web/net/cookies/crw_wk_http_cookie_store.mm
+++ b/ios/web/net/cookies/crw_wk_http_cookie_store.mm
@@ -82,7 +82,6 @@
 #pragma mark WKHTTPCookieStoreObserver method
 
 - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore*)cookieStore {
-  DCHECK(_HTTPCookieStore == cookieStore);
   _cachedCookies = nil;
 }
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index c8d5ea05..1f228f8 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1852,6 +1852,7 @@
     "data/ssl/certificates/bad_validity.pem",
     "data/ssl/certificates/can_sign_http_exchanges_draft_extension.pem",
     "data/ssl/certificates/can_sign_http_exchanges_draft_extension_invalid.pem",
+    "data/ssl/certificates/cert-manager.com-chain.pem",
     "data/ssl/certificates/client-empty-password.p12",
     "data/ssl/certificates/client-nokey.p12",
     "data/ssl/certificates/client-null-password.p12",
@@ -1902,7 +1903,6 @@
     "data/ssl/certificates/ct-test-embedded-with-intermediate-preca-chain.pem",
     "data/ssl/certificates/ct-test-embedded-with-preca-chain.pem",
     "data/ssl/certificates/ct-test-embedded-with-uids.pem",
-    "data/ssl/certificates/daltonridgeapts.com-chain.pem",
     "data/ssl/certificates/dec_2017.pem",
     "data/ssl/certificates/diginotar_cyber_ca.pem",
     "data/ssl/certificates/diginotar_pkioverheid.pem",
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index ca01616..545db16 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -1485,7 +1485,6 @@
     const char* const file;
     bool is_valid_too_long;
   } tests[] = {
-      {"daltonridgeapts.com-chain.pem", false},
       {"start_after_expiry.pem", true},
       {"pre_br_validity_ok.pem", false},
       {"pre_br_validity_bad_121.pem", true},
@@ -1518,20 +1517,19 @@
   }
 }
 
-// TODO(https://crbug.com/1214778): Disabled due to expired certificate.
-TEST_P(CertVerifyProcInternalTest, DISABLED_TestKnownRoot) {
+TEST_P(CertVerifyProcInternalTest, TestKnownRoot) {
   base::FilePath certs_dir = GetTestCertsDirectory();
   scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile(
-      certs_dir, "daltonridgeapts.com-chain.pem", X509Certificate::FORMAT_AUTO);
+      certs_dir, "cert-manager.com-chain.pem", X509Certificate::FORMAT_AUTO);
   ASSERT_TRUE(cert_chain);
 
   int flags = 0;
   CertVerifyResult verify_result;
   int error =
-      Verify(cert_chain.get(), "daltonridgeapts.com", flags,
+      Verify(cert_chain.get(), "ov-validation.cert-manager.com", flags,
              CRLSet::BuiltinCRLSet().get(), CertificateList(), &verify_result);
   EXPECT_THAT(error, IsOk()) << "This test relies on a real certificate that "
-                             << "expires on May 28, 2021. If failing on/after "
+                             << "expires on June 2, 2022. If failing on/after "
                              << "that date, please disable and file a bug "
                              << "against rsleevi.";
   EXPECT_TRUE(verify_result.is_issued_by_known_root);
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README
index 1ce0317..448aa2b 100644
--- a/net/data/ssl/certificates/README
+++ b/net/data/ssl/certificates/README
@@ -51,9 +51,9 @@
      All files are from the src/test/testdada directory in
      https://code.google.com/p/certificate-transparency/
 
-- daltonridgeapts.com-chain.pem : A long-lived (39 month), BR compliant,
-     non-EV certificate, issued by a public trust anchor, and valid for the
-     domain daltonridgeapts.com.
+- cert-manager.com-chain.pem : An OV certificate issued by a public trust
+    anchor valid for the domain ov-validation.cert-manager.com, and which
+    expires on 2022-06-22.
 
 - gms.hongleong.com.my-verisign-chain.pem: A certificate chain for
   gms.hongleong.com.my issued by VeriSign Class 3 Public Primary Certification
diff --git a/net/data/ssl/certificates/cert-manager.com-chain.pem b/net/data/ssl/certificates/cert-manager.com-chain.pem
new file mode 100644
index 0000000..5160d58
--- /dev/null
+++ b/net/data/ssl/certificates/cert-manager.com-chain.pem
@@ -0,0 +1,133 @@
+-----BEGIN CERTIFICATE-----
+MIIHOzCCBiOgAwIBAgIRAIWeFEqrk27xKKnZgPjlsSgwDQYJKoZIhvcNAQELBQAw
+gZUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE9MDsGA1UE
+AxM0U2VjdGlnbyBSU0EgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNl
+cnZlciBDQTAeFw0yMTA2MDIwMDAwMDBaFw0yMjA2MDIyMzU5NTlaMIGPMQswCQYD
+VQQGEwJERTETMBEGA1UEBwwKR8O2dHRpbmdlbjFCMEAGA1UEChM5R2VzZWxsc2No
+YWZ0IGZ1ZXIgd2lzc2Vuc2NoYWZ0bGljaGUgRGF0ZW52ZXJhcmJlaXR1bmcgbWJI
+MScwJQYDVQQDEx5vdi12YWxpZGF0aW9uLmNlcnQtbWFuYWdlci5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCayY1pJLAqmoVOJ1UWGfo//jiCJFBd
+fjs0fblshyxi1oyd8pUaMflgzkGFC4rs949ovbeQQ66bsuSTN2h+q3qaTAnZ5APD
+cFCpBsvxwQB0XwRkcTFGynANhXL3kJLAwpdU/oAcN46RA+rDXRz9ZFYwXf30IbCd
+AAVldAFZNwh3Zo2UdjElerC4PoMsk2vdcayep3Xh9YpNhaeaBiFckoRJ+jPnYdoD
+QTr4eLvVOeTcjSUmFzrqmmItJbplo8ZVk8O4X7ImLCXzsxtvx5GlAsaGGc9z1/uj
+lOl+w8hXf3wfPWXwacZ5XL+ewZD4+qSbr2NpC3sxv8C8dEdzMH+t3nstAgMBAAGj
+ggOIMIIDhDAfBgNVHSMEGDAWgBQX2dYlJ2f5McJJQ9kwNkSMbKlP6zAdBgNVHQ4E
+FgQUelyvC2sF6TNHcy9PXU1XtECFqEwwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB
+/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEoGA1UdIARDMEEw
+NQYMKwYBBAGyMQECAQMEMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5j
+b20vQ1BTMAgGBmeBDAECAjBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLnNl
+Y3RpZ28uY29tL1NlY3RpZ29SU0FPcmdhbml6YXRpb25WYWxpZGF0aW9uU2VjdXJl
+U2VydmVyQ0EuY3JsMIGKBggrBgEFBQcBAQR+MHwwVQYIKwYBBQUHMAKGSWh0dHA6
+Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1JTQU9yZ2FuaXphdGlvblZhbGlkYXRp
+b25TZWN1cmVTZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNl
+Y3RpZ28uY29tME0GA1UdEQRGMESCHm92LXZhbGlkYXRpb24uY2VydC1tYW5hZ2Vy
+LmNvbYIid3d3Lm92LXZhbGlkYXRpb24uY2VydC1tYW5hZ2VyLmNvbTCCAX8GCisG
+AQQB1nkCBAIEggFvBIIBawFpAHcARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy
+/HD+bUcAAAF5zXRtkQAABAMASDBGAiEAkF6ook74Xg6nSxBNKJcGw9/xPOUj3Uqk
+Tpb4Lq0aV9UCIQDxK/mVll3m1RdOG10txMADyM3hCLGirgH+Ka+Xf5QZiAB2AEHI
+yrHfIkZKEMahOglCh15OMYsbA+vrS8do8JBilgb2AAABec10bU4AAAQDAEcwRQIg
+AtJ/uzcRqV9fi+kTzC+2pcVgRfm5fbcMeSPqsPLQE6MCIQCv363LIbnFKqCy6P1A
+psgPD7GPbQNN15rLYJJFHIBg/gB2ACl5vvCeOTkh8FZzn2Old+W+V32cYAr4+U1d
+JlwlXceEAAABec10bSkAAAQDAEcwRQIgGMS9cGiANBz52/6QmgcBgkBZZOifgqB3
+BNOmxUzpcAACIQCL039lwP9tZu7TX4ESSVo/M+dxls3S1dRTb6/5lS/J3zANBgkq
+hkiG9w0BAQsFAAOCAQEAZvI38uuTRilCDmoYpmgT2vPDb6lZ6qCP6rOKDYUT+QXC
+joA0Y97SNoVQiSEtgwFwfvUsrjwcC9XZvIQ6D4HWJCeqV47Mkq+kfOJ+IsDyfyYd
+ehCDoJSVmUA+ULwt419V7KDPmgroViSAwEwKgvUocNkMCVkk4zniWFq2LSMETSbZ
+yI/uRcF24Gx4YYRoBf6Wxei7fkZuRhd/JhOH7ULEM+7PVqur7Gdj9qW0zzsHDJp6
+cTvB1Tz0ZmV8Js4d8hOU7K8GGvtEgS28pUn03PrV2cxgUur4PaqWTez+V6fXcWaH
+E77devYJHdegqyOZHLTtxXlM+pEpxYm9fsJ9Rf3iDg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGGTCCBAGgAwIBAgIQE31TnKp8MamkM3AZaIR6jTANBgkqhkiG9w0BAQwFADCB
+iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
+cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
+BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
+MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBlTELMAkGA1UEBhMCR0IxGzAZBgNV
+BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
+ChMPU2VjdGlnbyBMaW1pdGVkMT0wOwYDVQQDEzRTZWN0aWdvIFJTQSBPcmdhbml6
+YXRpb24gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAnJMCRkVKUkiS/FeN+S3qU76zLNXYqKXsW2kDwB0Q
+9lkz3v4HSKjojHpnSvH1jcM3ZtAykffEnQRgxLVK4oOLp64m1F06XvjRFnG7ir1x
+on3IzqJgJLBSoDpFUd54k2xiYPHkVpy3O/c8Vdjf1XoxfDV/ElFw4Sy+BKzL+k/h
+fGVqwECn2XylY4QZ4ffK76q06Fha2ZnjJt+OErK43DOyNtoUHZZYQkBuCyKFHFEi
+rsTIBkVtkuZntxkj5Ng2a4XQf8dS48+wdQHgibSov4o2TqPgbOuEQc6lL0giE5dQ
+YkUeCaXMn2xXcEAG2yDoG9bzk4unMp63RBUJ16/9fAEc2wIDAQABo4IBbjCCAWow
+HwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFBfZ1iUn
+Z/kxwklD2TA2RIxsqU/rMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/
+AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYG
+BFUdIAAwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl
+cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy
+bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy
+dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ
+aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAThNA
+lsnD5m5bwOO69Bfhrgkfyb/LDCUW8nNTs3Yat6tIBtbNAHwgRUNFbBZaGxNh10m6
+pAKkrOjOzi3JKnSj3N6uq9BoNviRrzwB93fVC8+Xq+uH5xWo+jBaYXEgscBDxLmP
+bYox6xU2JPti1Qucj+lmveZhUZeTth2HvbC1bP6mESkGYTQxMD0gJ3NR0N6Fg9N3
+OSBGltqnxloWJ4Wyz04PToxcvr44APhL+XJ71PJ616IphdAEutNCLFGIUi7RPSRn
+R+xVzBv0yjTqJsHe3cQhifa6ezIejpZehEU4z4CqN2mLYBd0FUiRnG3wTqN3yhsc
+SPr5z0noX0+FCuKPkBurcEya67emP7SsXaRfz+bYipaQ908mgWB2XQ8kd5GzKjGf
+FlqyXYwcKapInI5v03hAcNt37N3j0VcFcC3mSZiIBYRiBXBWdoY5TtMibx3+bfEO
+s2LEPMvAhblhHrrhFYBZlAyuBbuMf1a+HNJav5fyakywxnB2sJCNwQs2uRHY1ihc
+6k/+JLcYCpsM0MF8XPtpvcyiTcaQvKZN8rG61ppnW5YCUtCC+cQKXA0o4D/I+pWV
+idWkvklsQLI+qGu41SWyxP7x09fn1txDAXYw+zuLXfdKiXyaNb78yvBXAfCNP6CH
+MntHWpdLgtJmwsQt6j8k9Kf5qLnjatkYYaA7jBU=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7
+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
+VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
+AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4
+MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5
+MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO
+ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI
+s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG
+vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ
+Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb
+IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0
+tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E
+xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV
+icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5
+D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ
+WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ
+5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG
+KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg
+EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID
+ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG
+BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t
+L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr
+BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA
+A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+
+rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+
+/czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA
+CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F
+zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA
+vGp4z7h/jnZymQyd/teRCBaho1+V
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/certificates/daltonridgeapts.com-chain.pem b/net/data/ssl/certificates/daltonridgeapts.com-chain.pem
deleted file mode 100644
index dee9cff3..0000000
--- a/net/data/ssl/certificates/daltonridgeapts.com-chain.pem
+++ /dev/null
@@ -1,110 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFRTCCBC2gAwIBAgIJAJFVij12QTNzMA0GCSqGSIb3DQEBCwUAMIG0MQswCQYD
-VQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEa
-MBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0
-cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2Vj
-dXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE4MDIyODE5NDUwNloX
-DTIxMDUyODE5NDUwNlowQTEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRh
-dGVkMRwwGgYDVQQDExNkYWx0b25yaWRnZWFwdHMuY29tMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEAqwLMdmbWVNeA7EHm6XCy6PbJpzNsuu0tXvVIbwbF
-UID2QU/1sABgGGf/etL3m2WUn7hA3Mqzu38ZA+A115w9ATQ6CpLvNNysNPNBcVRt
-jfKkH6PTx2s3BIQ9nDeZK04RPDeqrLZpexJ6RuCqNdH1+8HeP56s8M3g+ZU/azRt
-G3Xml32bunoDBK+KlJIgCSQpsqmRfwgQqzPMZj3X0oJt7fdf8bE2uXP55W4WRuu7
-q738To282Zrb3m+HgrUHk2cz8fePlLLIN8xrKXru8k+oxtgi9hsNLxsORGnCLnE/
-KW4oHoNhPLqO5pd00u5ZwHGuHuvwDY+417hJaXNVSXVVAQIDAQABo4IByjCCAcYw
-DAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYD
-VR0PAQH/BAQDAgWgMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZ29kYWRk
-eS5jb20vZ2RpZzJzMS04MTEuY3JsMF0GA1UdIARWMFQwSAYLYIZIAYb9bQEHFwEw
-OTA3BggrBgEFBQcCARYraHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9y
-ZXBvc2l0b3J5LzAIBgZngQwBAgEwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzAB
-hhhodHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wQAYIKwYBBQUHMAKGNGh0dHA6Ly9j
-ZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9nZGlnMi5jcnQwHwYD
-VR0jBBgwFoAUQMK9J47MNIMwojPX+2yz8LQsgM4wNwYDVR0RBDAwLoITZGFsdG9u
-cmlkZ2VhcHRzLmNvbYIXd3d3LmRhbHRvbnJpZGdlYXB0cy5jb20wHQYDVR0OBBYE
-FG7ojZg+vlPb8iPiyN0oeSAYaW+8MA0GCSqGSIb3DQEBCwUAA4IBAQCvLidW3At+
-fBN8JJBzL8rM/fVk80033A70EKt4O0+DSk+a6AwMcn0SIC3N6/y3pE+XvqnDaL2F
-jvuOgO16H6hhmRyknx+ejIzLa/NKrhAhwgAIOSGXRNoOHThZe8Apnv07j61LPLr4
-SV4RF06zU8TgkltU4WodyCikeADwbIH/W0LnJ3JVxXKrtlYTGqd47LMHlSNRoZeg
-g8pdIxBr4DfZlxhmmyEyGGloLABRzsBQWx2wlbWtpL95ot0FoTnJRc7Z933mzmsT
-OTG6S24vzMEG7zziz1GWsZnUaSjE4OAvv4yBprLN7zp7MkKCzzddWh9nZTXudjXO
-YS6/ctGzpcFO
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
-EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
-ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3
-MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
-EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE
-CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD
-EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD
-BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv
-K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e
-cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY
-pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n
-eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB
-AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
-HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv
-9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v
-b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n
-b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG
-CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv
-MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz
-91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2
-RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi
-DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11
-GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x
-LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVT
-MSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNVBAsTKEdv
-IERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMTAx
-MDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
-B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHku
-Y29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1
-dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3Fi
-CPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjHMgGxBT4H
-Tu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6or6KFWp/
-3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T3UYH3go+
-6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6eMAo5zvGI
-gPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51iruF9G/M7E
-GwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/eMB8GA1Ud
-IwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgwJjAkBggr
-BgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQrMCkwJ6Al
-oCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNVHSAEPzA9
-MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNv
-bS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEacke+1bMc8d
-H2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVnOQoWCcWg
-OJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYggHFCJyNwq
-9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY7NmuHDKO
-KHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzdsyqUvMQg3
-qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcYQFHfjDCm
-rw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
-MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
-YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
-MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
-ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
-MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
-ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
-PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
-wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
-EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
-avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
-YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
-sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
-/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
-IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
-ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
-OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
-TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
-HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
-dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
-ReYNnyicsbkqWletNw+vHX/bvZ8=
------END CERTIFICATE-----
diff --git a/services/preferences/public/cpp/dictionary_value_update.cc b/services/preferences/public/cpp/dictionary_value_update.cc
index 02a2653..9db22ff 100644
--- a/services/preferences/public/cpp/dictionary_value_update.cc
+++ b/services/preferences/public/cpp/dictionary_value_update.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace prefs {
 
@@ -194,7 +195,12 @@
 bool DictionaryValueUpdate::GetIntegerWithoutPathExpansion(
     base::StringPiece key,
     int* out_value) const {
-  return value_->GetIntegerWithoutPathExpansion(key, out_value);
+  absl::optional<int> value = value_->FindIntKey(key);
+  if (!value)
+    return false;
+
+  *out_value = value.value();
+  return true;
 }
 
 bool DictionaryValueUpdate::GetDoubleWithoutPathExpansion(
diff --git a/services/viz/public/cpp/compositing/copy_output_result_mojom_traits.cc b/services/viz/public/cpp/compositing/copy_output_result_mojom_traits.cc
index a64d220e..fded376 100644
--- a/services/viz/public/cpp/compositing/copy_output_result_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/copy_output_result_mojom_traits.cc
@@ -99,8 +99,12 @@
   if (result->format() != viz::CopyOutputResult::Format::RGBA_BITMAP)
     return absl::nullopt;
   auto scoped_bitmap = result->ScopedAccessSkBitmap();
-  if (!scoped_bitmap.bitmap().readyToDraw())
+  if (!scoped_bitmap.bitmap().readyToDraw()) {
+    // During shutdown or switching to background on Android, Chrome will
+    // release GPU context, it will release mapped GPU memory which is used
+    // in SkBitmap, in that case, a null bitmap will be sent.
     return absl::nullopt;
+  }
   return scoped_bitmap;
 }
 
@@ -180,8 +184,15 @@
       absl::optional<SkBitmap> bitmap_opt;
       if (!data.ReadBitmap(&bitmap_opt))
         return false;
-      if (!bitmap_opt)
-        return false;
+      if (!bitmap_opt) {
+        // During shutdown or switching to background on Android, Chrome will
+        // release GPU context, it will release mapped GPU memory which is used
+        // in SkBitmap, in that case, the sender will send a null bitmap. So we
+        // should consider the copy output result is empty.
+        *out_p =
+            std::make_unique<viz::CopyOutputResult>(format, gfx::Rect(), false);
+        return true;
+      }
       if (!bitmap_opt->readyToDraw())
         return false;
 
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 6a66a75..5310d13 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -255,6 +255,8 @@
     "ext/opacity_filter_canvas.h",
     "ext/recursive_gaussian_convolution.cc",
     "ext/recursive_gaussian_convolution.h",
+    "ext/rgba_to_yuva.cc",
+    "ext/rgba_to_yuva.h",
     "ext/skia_histogram.cc",
     "ext/skia_histogram.h",
     "ext/skia_memory_dump_provider.cc",
diff --git a/skia/ext/rgba_to_yuva.cc b/skia/ext/rgba_to_yuva.cc
new file mode 100644
index 0000000..8908115
--- /dev/null
+++ b/skia/ext/rgba_to_yuva.cc
@@ -0,0 +1,81 @@
+// Copyright 2021 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 "skia/ext/rgba_to_yuva.h"
+
+#include "base/notreached.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkColorMatrix.h"
+
+namespace skia {
+
+void BlitRGBAToYUVA(sk_sp<SkImage> src_image,
+                    const SkRect& src_rect,
+                    sk_sp<SkSurface> dst_surfaces[SkYUVAInfo::kMaxPlanes],
+                    const SkYUVAInfo& dst_yuva_info,
+                    const SkRect& dst_rect) {
+  // TODO(https://crbug.com/1206168): These color matrices are copied directly
+  // from kRGBtoYColorWeights et al in the gpu::GLHelperScaling::
+  // CreateI420Planerizer method this is code is replacing. This corresponds
+  // to hard-coding kRec601_Limited_SkYUVColorSpace. This should look up the
+  // matrix based on |dst_yuva_info|.
+  SkColorMatrix rgb_to_yuv(0.257f, 0.504f, 0.098f, 0.000f, 0.0625f,    //
+                           -0.148f, -0.291f, 0.439f, 0.000f, 0.5000f,  //
+                           0.439f, -0.368f, -0.071f, 0.000f, 0.5000f,  //
+                           0.000f, 0.000f, 0.000f, 0.000f, 1.0000f);
+
+  // Permutation matrices to select the appropriate YUVA channels for each
+  // output plane.
+  const SkColorMatrix xxxY(0, 0, 0, 0, 0,  //
+                           0, 0, 0, 0, 0,  //
+                           0, 0, 0, 0, 0,  //
+                           1, 0, 0, 0, 0);
+  const SkColorMatrix UVx1(0, 1, 0, 0, 0,  //
+                           0, 0, 1, 0, 0,  //
+                           0, 0, 0, 0, 0,  //
+                           0, 0, 0, 1, 0);
+
+  // Only Y_UV has been tested.
+  SkColorMatrix permutation_matrices[SkYUVAInfo::kMaxPlanes];
+  switch (dst_yuva_info.planeConfig()) {
+    case SkYUVAInfo::PlaneConfig::kY_UV:
+      permutation_matrices[0] = xxxY;
+      permutation_matrices[1] = UVx1;
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  // Blit each plane.
+  for (int plane = 0; plane < dst_yuva_info.numPlanes(); ++plane) {
+    SkColorMatrix color_matrix = rgb_to_yuv;
+    color_matrix.postConcat(permutation_matrices[plane]);
+
+    SkSamplingOptions sampling_options(SkFilterMode::kLinear);
+
+    SkPaint paint;
+    paint.setColorFilter(SkColorFilters::Matrix(color_matrix));
+
+    float subsampling_factors[2] = {
+        static_cast<float>(dst_surfaces[plane]->width()) /
+            dst_yuva_info.dimensions().width(),
+        static_cast<float>(dst_surfaces[plane]->height()) /
+            dst_yuva_info.dimensions().height(),
+    };
+    SkRect plane_dst_rect =
+        SkRect::MakeXYWH(dst_rect.x() * subsampling_factors[0],
+                         dst_rect.y() * subsampling_factors[1],
+                         dst_rect.width() * subsampling_factors[0],
+                         dst_rect.height() * subsampling_factors[1]);
+
+    dst_surfaces[plane]->getCanvas()->drawImageRect(
+        src_image, src_rect, plane_dst_rect, sampling_options, &paint,
+        SkCanvas::kFast_SrcRectConstraint);
+  }
+}
+
+}  // namespace skia
diff --git a/skia/ext/rgba_to_yuva.h b/skia/ext/rgba_to_yuva.h
new file mode 100644
index 0000000..d6c7b483
--- /dev/null
+++ b/skia/ext/rgba_to_yuva.h
@@ -0,0 +1,26 @@
+// Copyright 2021 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 SKIA_EXT_RGBA_TO_YUVA_H_
+#define SKIA_EXT_RGBA_TO_YUVA_H_
+
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/core/SkYUVAInfo.h"
+
+namespace skia {
+
+// Copy `src_image` from RGBA to the YUVA planes specified in `dst_surfaces`,
+// using the color space and plane configuration information specified in
+// `dst_yuva_info`.
+SK_API void BlitRGBAToYUVA(
+    sk_sp<SkImage> src_image,
+    const SkRect& src_rect,
+    sk_sp<SkSurface> dst_surfaces[SkYUVAInfo::kMaxPlanes],
+    const SkYUVAInfo& dst_yuva_info,
+    const SkRect& dst_rect);
+
+}  // namespace skia
+
+#endif  // SKIA_EXT_RGBA_TO_YUVA_H_
diff --git a/storage/browser/file_system/obfuscated_file_util.h b/storage/browser/file_system/obfuscated_file_util.h
index 81765c5..98d8db7 100644
--- a/storage/browser/file_system/obfuscated_file_util.h
+++ b/storage/browser/file_system/obfuscated_file_util.h
@@ -215,8 +215,8 @@
   // Helper method to create an obfuscated file util for regular
   // (temporary, persistent) file systems. Used only for testing.
   // Note: this is implemented in sandbox_file_system_backend_delegate.cc.
-  static ObfuscatedFileUtil* CreateForTesting(
-      SpecialStoragePolicy* special_storage_policy,
+  static std::unique_ptr<ObfuscatedFileUtil> CreateForTesting(
+      scoped_refptr<SpecialStoragePolicy> special_storage_policy,
       const base::FilePath& file_system_directory,
       leveldb::Env* env_override,
       bool is_incognito);
diff --git a/storage/browser/file_system/obfuscated_file_util_unittest.cc b/storage/browser/file_system/obfuscated_file_util_unittest.cc
index c955380..8c76db3 100644
--- a/storage/browser/file_system/obfuscated_file_util_unittest.cc
+++ b/storage/browser/file_system/obfuscated_file_util_unittest.cc
@@ -255,12 +255,11 @@
   }
 
   std::unique_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil(
-      SpecialStoragePolicy* storage_policy) {
-    return std::unique_ptr<ObfuscatedFileUtil>(
-        ObfuscatedFileUtil::CreateForTesting(
-            storage_policy, data_dir_path(),
-            is_incognito() ? incognito_leveldb_environment_.get() : nullptr,
-            is_incognito()));
+      scoped_refptr<SpecialStoragePolicy> storage_policy) {
+    return ObfuscatedFileUtil::CreateForTesting(
+        std::move(storage_policy), data_dir_path(),
+        is_incognito() ? incognito_leveldb_environment_.get() : nullptr,
+        is_incognito());
   }
 
   ObfuscatedFileUtil* ofu() {
@@ -698,7 +697,7 @@
 
   void MaybeDropDatabasesAliveCaseTestBody() {
     std::unique_ptr<ObfuscatedFileUtil> file_util =
-        CreateObfuscatedFileUtil(nullptr);
+        CreateObfuscatedFileUtil(/*storage_policy=*/nullptr);
     file_util->InitOriginDatabase(Origin(), true /*create*/);
     ASSERT_TRUE(file_util->origin_database_ != nullptr);
 
@@ -716,7 +715,7 @@
     // doesn't cause a crash for use after free.
     {
       std::unique_ptr<ObfuscatedFileUtil> file_util =
-          CreateObfuscatedFileUtil(nullptr);
+          CreateObfuscatedFileUtil(/*storage_policy=*/nullptr);
       file_util->InitOriginDatabase(Origin(), true /*create*/);
       file_util->db_flush_delay_seconds_ = 0;
       file_util->MarkUsed();
@@ -729,7 +728,7 @@
   void DestroyDirectoryDatabase_IsolatedTestBody() {
     storage_policy_->AddIsolated(origin_.GetURL());
     std::unique_ptr<ObfuscatedFileUtil> file_util =
-        CreateObfuscatedFileUtil(storage_policy_.get());
+        CreateObfuscatedFileUtil(/*storage_policy=*/storage_policy_);
     const FileSystemURL url = FileSystemURL::CreateForTest(
         origin_, kFileSystemTypePersistent, base::FilePath());
 
@@ -747,7 +746,7 @@
   void GetDirectoryDatabase_IsolatedTestBody() {
     storage_policy_->AddIsolated(origin_.GetURL());
     std::unique_ptr<ObfuscatedFileUtil> file_util =
-        CreateObfuscatedFileUtil(storage_policy_.get());
+        CreateObfuscatedFileUtil(storage_policy_);
     const FileSystemURL url = FileSystemURL::CreateForTest(
         origin_, kFileSystemTypePersistent, base::FilePath());
 
diff --git a/storage/browser/file_system/quota/quota_backend_impl_unittest.cc b/storage/browser/file_system/quota/quota_backend_impl_unittest.cc
index 84dc3a1af..fe6f140c 100644
--- a/storage/browser/file_system/quota/quota_backend_impl_unittest.cc
+++ b/storage/browser/file_system/quota/quota_backend_impl_unittest.cc
@@ -110,8 +110,9 @@
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     in_memory_env_ = leveldb_chrome::NewMemEnv("quota");
-    file_util_.reset(ObfuscatedFileUtil::CreateForTesting(
-        nullptr, data_dir_.GetPath(), in_memory_env_.get(), is_incognito()));
+    file_util_ = ObfuscatedFileUtil::CreateForTesting(
+        /*special_storage_policy=*/nullptr, data_dir_.GetPath(),
+        in_memory_env_.get(), is_incognito());
     backend_ = std::make_unique<QuotaBackendImpl>(
         file_task_runner(), file_util_.get(), &file_system_usage_cache_,
         quota_manager_proxy_.get());
diff --git a/storage/browser/file_system/sandbox_file_system_backend_delegate.cc b/storage/browser/file_system/sandbox_file_system_backend_delegate.cc
index 1d6924d..78e4068 100644
--- a/storage/browser/file_system/sandbox_file_system_backend_delegate.cc
+++ b/storage/browser/file_system/sandbox_file_system_backend_delegate.cc
@@ -705,15 +705,15 @@
 
 // Declared in obfuscated_file_util.h.
 // static
-ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting(
-    SpecialStoragePolicy* special_storage_policy,
+std::unique_ptr<ObfuscatedFileUtil> ObfuscatedFileUtil::CreateForTesting(
+    scoped_refptr<SpecialStoragePolicy> special_storage_policy,
     const base::FilePath& file_system_directory,
     leveldb::Env* env_override,
     bool is_incognito) {
-  return new ObfuscatedFileUtil(special_storage_policy, file_system_directory,
-                                env_override,
-                                base::BindRepeating(&GetTypeStringForURL),
-                                GetKnownTypeStrings(), nullptr, is_incognito);
+  return std::make_unique<ObfuscatedFileUtil>(
+      std::move(special_storage_policy), file_system_directory, env_override,
+      base::BindRepeating(&GetTypeStringForURL), GetKnownTypeStrings(),
+      /*sandbox_delegate=*/nullptr, is_incognito);
 }
 
 }  // namespace storage
diff --git a/third_party/blink/common/storage_key/storage_key_unittest.cc b/third_party/blink/common/storage_key/storage_key_unittest.cc
index 8a8d2e6b8..bac69171 100644
--- a/third_party/blink/common/storage_key/storage_key_unittest.cc
+++ b/third_party/blink/common/storage_key/storage_key_unittest.cc
@@ -10,7 +10,7 @@
 namespace blink {
 
 // Test when a constructed StorageKey object should be considered valid/opaque.
-TEST(BlinkStorageKeyTest, ConstructionValidity) {
+TEST(StorageKeyTest, ConstructionValidity) {
   StorageKey empty = StorageKey();
   EXPECT_TRUE(empty.opaque());
 
@@ -25,7 +25,7 @@
 }
 
 // Test that StorageKeys are/aren't equivalent as expected.
-TEST(BlinkStorageKeyTest, Equivalance) {
+TEST(StorageKeyTest, Equivalance) {
   url::Origin origin1 = url::Origin::Create(GURL("https://example.com"));
   url::Origin origin2 = url::Origin::Create(GURL("https://test.example"));
   url::Origin origin3 = url::Origin();
@@ -61,7 +61,7 @@
 }
 
 // Test that StorageKeys Serialize to the expected value.
-TEST(BlinkStorageKeyTest, Serialize) {
+TEST(StorageKeyTest, Serialize) {
   std::string example = "https://example.com/";
   std::string example_no_trailing_slash = "https://example.com";
   std::string test = "https://test.example/";
@@ -77,7 +77,7 @@
 }
 
 // Test that deserialized StorageKeys are valid/opaque as expected.
-TEST(BlinkStorageKeyTest, Deserialize) {
+TEST(StorageKeyTest, Deserialize) {
   std::string example = "https://example.com/";
   std::string test = "https://test.example/";
   std::string wrong = "I'm not a valid URL.";
@@ -94,7 +94,7 @@
 }
 
 // Test that string -> StorageKey test function performs as expected.
-TEST(BlinkStorageKeyTest, CreateFromStringForTesting) {
+TEST(StorageKeyTest, CreateFromStringForTesting) {
   std::string example = "https://example.com/";
   std::string wrong = "I'm not a valid URL.";
 
@@ -110,7 +110,7 @@
 
 // Test that a StorageKey, constructed by deserializing another serialized
 // StorageKey, is equivalent to the original.
-TEST(BlinkStorageKeyTest, SerializeDeserialize) {
+TEST(StorageKeyTest, SerializeDeserialize) {
   url::Origin origin1 = url::Origin::Create(GURL("https://example.com"));
   url::Origin origin2 = url::Origin::Create(GURL("https://test.example"));
 
diff --git a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
index 319b693..048ad17 100644
--- a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
+++ b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
@@ -11,11 +11,12 @@
 // operations on the main frame, mainly generating and removing fragments.
 // Implemented in renderer.
 interface TextFragmentReceiver {
-  // Cancel text fragment generation if any active.
+  // Cancel text fragment generation if in progress.
   Cancel();
 
-  // Request text fragment selector according to
-  // https://github.com/WICG/scroll-to-text-fragment#proposed-solution.
+  // Request that the receiver generate a text fragment selector based on the
+  // currently selected text on the page. See also:
+  // https://github.com/WICG/scroll-to-text-fragment.
   RequestSelector() => (string selector);
 
   // Dismiss all text fragments from the current main frame at the time the
@@ -28,6 +29,7 @@
   // Request text fragment selectors for existing highlights.
   GetExistingSelectors() => (array<string> selectors);
 
-  // Request the first text fragment rectangle relative to the viewport
+  // Request the bounding rectangle, relative to the viewport, of the first
+  // found match. Returns an empty rectangle if no matches are found.
   ExtractFirstFragmentRect() => (gfx.mojom.Rect bounds);
 };
diff --git a/third_party/blink/renderer/README.md b/third_party/blink/renderer/README.md
index bf03536f..97df608 100644
--- a/third_party/blink/renderer/README.md
+++ b/third_party/blink/renderer/README.md
@@ -84,6 +84,16 @@
 
 All of the above applies to `bindings/modules` and `modules/`.
 
+### `extensions/`
+
+The `extensions/` directory contains embedder-specific, not-web-exposed APIs (e.g., not-web-exposed APIs for Chromium OS etc).
+The directory is useful to implement embedder-specific, not-web-exposed APIs
+using Blink technologies for web-exposed APIs like WebIDL, V8 bindings and Oilpan.
+
+Remember that you should not implement web-exposed APIs in `extensions/`. Web-exposed APIs should go through the standardization process and be implemented in `core/` or `modules/`. Also, per [the Chromium contributor guideline](https://chromium.googlesource.com/chromium/src/+/main/docs/contributing.md#code-guidelines), code that is not used by Chromium should not be added to `extensions/`.
+
+In terms of dependencies, `extensions/` can depend on `modules/`, `core/` and `platform/`, but not vice versa.
+
 ### `controller/`
 
 The `controller/` directory contains the system infrastructure
@@ -96,8 +106,7 @@
 however most of the features should go to other directories.
 Consult `controller/` OWNERS when in doubt.
 
-In terms of dependencies, `controller/` can depend on `core/`, `platform/` and `modules/`,
-but not vice versa.
+In terms of dependencies, `controller/` can depend on `extensions/`, `modules/`, `core/` and `platform/`, but not vice versa.
 
 ### `build/`
 
@@ -111,6 +120,7 @@
 
 - `public/web`
 - `controller/`
+- `extensions/`
 - `modules/` and `bindings/modules`
 - `core/` and `bindings/core`
 - `platform/`
@@ -158,8 +168,7 @@
 
 ### Mojo
 
-`core/`, `modules/`, `bindings/`, `platform/` and `controller/` can use Mojo and
-directly talk to the browser process. This allows removal of unnecessary
+Blink can use Mojo and directly talk to the browser process. This allows removal of unnecessary
 public APIs and abstraction layers and it is highly recommended.
 
 ## Contact
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 380bbb7..96d82f6a 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -2138,6 +2138,9 @@
     ancestor->ClearChildNeedsReattachLayoutTree();
   }
   layout_tree_rebuild_root_.Clear();
+
+  if (IsA<HTMLHtmlElement>(root_element) || IsA<HTMLBodyElement>(root_element))
+    PropagateWritingModeAndDirectionToHTMLRoot();
 }
 
 void StyleEngine::UpdateStyleAndLayoutTree() {
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ac289f7..c37dd643 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2710,8 +2710,8 @@
 
   markers_->PrepareForDestruction();
 
-  if (GetFrame()->GetTextFragmentSelectorGenerator())
-    GetFrame()->GetTextFragmentSelectorGenerator()->ClearSelection();
+  if (TextFragmentHandler* handler = GetFrame()->GetTextFragmentHandler())
+    handler->DidDetachDocumentOrFrame();
 
   GetPage()->DocumentDetached(this);
 
diff --git a/third_party/blink/renderer/core/editing/range_in_flat_tree.h b/third_party/blink/renderer/core/editing/range_in_flat_tree.h
index c1091b5..edc941b 100644
--- a/third_party/blink/renderer/core/editing/range_in_flat_tree.h
+++ b/third_party/blink/renderer/core/editing/range_in_flat_tree.h
@@ -12,7 +12,8 @@
 
 // This is a wrapper class for a range in flat tree that is relocatable by
 // relacating the start and end positions in DOM tree.
-class RangeInFlatTree final : public GarbageCollected<RangeInFlatTree> {
+class CORE_EXPORT RangeInFlatTree final
+    : public GarbageCollected<RangeInFlatTree> {
  public:
   RangeInFlatTree(const PositionInFlatTree& start,
                   const PositionInFlatTree& end);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 932b271..ad14a9c3 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -822,9 +822,8 @@
     content_capture_manager_ = nullptr;
   }
 
-  if (text_fragment_handler_) {
-    text_fragment_handler_->GetTextFragmentSelectorGenerator()->Detach();
-  }
+  if (text_fragment_handler_)
+    text_fragment_handler_->DidDetachDocumentOrFrame();
 
   GetBackForwardCacheBufferLimitTracker().DidRemoveFrameFromBackForwardCache(
       total_bytes_buffered_while_in_back_forward_cache_);
@@ -861,6 +860,10 @@
 
 BackgroundColorPaintImageGenerator*
 LocalFrame::GetBackgroundColorPaintImageGenerator() {
+  // There is no compositor thread in certain testing environment, and we should
+  // not composite background color animation in those cases.
+  if (!Thread::CompositorThread())
+    return nullptr;
   LocalFrame& local_root = LocalFrameRoot();
   // One background color paint worklet per root frame.
   if (!local_root.background_color_paint_image_generator_) {
@@ -4089,11 +4092,4 @@
   return DomWindow()->GetTextSuggestionController();
 }
 
-TextFragmentSelectorGenerator* LocalFrame::GetTextFragmentSelectorGenerator()
-    const {
-  if (!text_fragment_handler_)
-    return nullptr;
-  return text_fragment_handler_->GetTextFragmentSelectorGenerator();
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 75933390..31caa4651 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -131,7 +131,6 @@
 class SmoothScrollSequencer;
 class SpellChecker;
 class TextFragmentHandler;
-class TextFragmentSelectorGenerator;
 class TextSuggestionController;
 class VirtualKeyboardOverlayChangedObserver;
 class WebContentSettingsClient;
@@ -806,8 +805,6 @@
     return text_fragment_handler_;
   }
 
-  TextFragmentSelectorGenerator* GetTextFragmentSelectorGenerator() const;
-
   LoaderFreezeMode GetLoaderFreezeMode();
 
   bool SwapIn();
diff --git a/third_party/blink/renderer/core/html/html_html_element.cc b/third_party/blink/renderer/core/html/html_html_element.cc
index da95b0e..b8606ff 100644
--- a/third_party/blink/renderer/core/html/html_html_element.cc
+++ b/third_party/blink/renderer/core/html/html_html_element.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/html/html_body_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h"
@@ -133,7 +134,7 @@
     scoped_refptr<const ComputedStyle> style) {
   DCHECK(style);
   DCHECK(GetDocument().InStyleRecalc());
-  if (const Element* body_element = GetDocument().body()) {
+  if (const Element* body_element = GetDocument().FirstBodyElement()) {
     if (const ComputedStyle* body_style = body_element->GetComputedStyle()) {
       if (NeedsLayoutStylePropagation(*style, *body_style))
         return CreateLayoutStyle(*style, *body_style);
@@ -143,25 +144,21 @@
 }
 
 void HTMLHtmlElement::PropagateWritingModeAndDirectionFromBody() {
-  // Will be propagated in HTMLHtmlElement::AttachLayoutTree().
-  if (NeedsReattachLayoutTree())
+  if (NeedsReattachLayoutTree()) {
+    // This means we are being called from RecalcStyle(). Since we need to
+    // reattach the layout tree, we will re-enter this method from
+    // RebuildLayoutTree().
     return;
-  LayoutObject* layout_object = GetLayoutObject();
-  if (!layout_object)
-    return;
-  const ComputedStyle* style = GetComputedStyle();
-  // If we have a layout object, and we are not marked for re-attachment, we are
-  // guaranteed to have a non-null ComputedStyle.
-  DCHECK(style);
-  const ComputedStyle* propagated_style = nullptr;
-  if (const Element* body = GetDocument().body())
-    propagated_style = body->GetComputedStyle();
-  if (!propagated_style)
-    propagated_style = style;
-  if (NeedsLayoutStylePropagation(layout_object->StyleRef(),
-                                  *propagated_style)) {
+  }
+  if (Element* body_element = GetDocument().FirstBodyElement()) {
+    // Same as above.
+    if (body_element->NeedsReattachLayoutTree())
+      return;
+  }
+
+  if (auto* layout_object = GetLayoutObject()) {
     scoped_refptr<const ComputedStyle> new_style =
-        CreateLayoutStyle(*style, *propagated_style);
+        LayoutStyleForElement(layout_object->Style());
     layout_object->SetStyle(new_style);
     // We need to propagate the style to text children because the used
     // writing-mode and direction affects text children. Child elements,
@@ -176,15 +173,4 @@
   }
 }
 
-void HTMLHtmlElement::AttachLayoutTree(AttachContext& context) {
-  scoped_refptr<const ComputedStyle> original_style = GetComputedStyle();
-  if (original_style)
-    SetComputedStyle(LayoutStyleForElement(original_style));
-
-  Element::AttachLayoutTree(context);
-
-  if (original_style)
-    SetComputedStyle(original_style);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_html_element.h b/third_party/blink/renderer/core/html/html_html_element.h
index a9054de..c0df6a0a 100644
--- a/third_party/blink/renderer/core/html/html_html_element.h
+++ b/third_party/blink/renderer/core/html/html_html_element.h
@@ -47,7 +47,6 @@
 
   bool IsURLAttribute(const Attribute&) const override;
   const CSSPropertyValueSet* AdditionalPresentationAttributeStyle() override;
-  void AttachLayoutTree(AttachContext&) override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.cc
index f62a528..940fbb1 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.cc
@@ -370,10 +370,14 @@
     float length_adjust_scale = text_length / (max_position - min_position);
     for (wtf_size_t k = i; k < j_plus_1; ++k) {
       SvgPerCharacterInfo& info = result_[k];
+      float original_x = *info.x;
+      float original_y = *info.y;
       if (horizontal_)
         *info.x = min_position + (*info.x - min_position) * length_adjust_scale;
       else
         *info.y = min_position + (*info.y - min_position) * length_adjust_scale;
+      info.text_length_shift_x += *info.x - original_x;
+      info.text_length_shift_y += *info.y - original_y;
       if (!info.middle && !info.text_length_resolved) {
         info.length_adjust_scale = length_adjust_scale;
         info.inline_size *= length_adjust_scale;
@@ -401,14 +405,29 @@
     // 2.4.5. Let shift = 0.
     shift = 0.0f;
     // 2.4.6. For each index k in the range [i,j]:
-    for (wtf_size_t k = i; k < j_plus_1; ++k) {
+    //  ==> This loop should run in visual order.
+    Vector<wtf_size_t> visual_indexes;
+    visual_indexes.ReserveCapacity(j_plus_1 - i);
+    for (wtf_size_t k = i; k < j_plus_1; ++k)
+      visual_indexes.push_back(k);
+    if (inline_node_.IsBidiEnabled()) {
+      std::sort(visual_indexes.begin(), visual_indexes.end(),
+                [&](wtf_size_t a, wtf_size_t b) {
+                  return result_[a].item_index < result_[b].item_index;
+                });
+    }
+
+    for (wtf_size_t k : visual_indexes) {
       SvgPerCharacterInfo& info = result_[k];
       // 2.4.6.1. Add shift to the x coordinate of the position in result[k], if
       // the "horizontal" flag is true, and to the y coordinate otherwise.
-      if (horizontal_)
+      if (horizontal_) {
         *info.x += shift;
-      else
+        info.text_length_shift_x += shift;
+      } else {
         *info.y += shift;
+        info.text_length_shift_y += shift;
+      }
       // 2.4.6.2. If the "middle" flag for result[k] is not true and k is not a
       // character in a resolved descendant node other than the first character
       // then shift = shift + small-delta.
@@ -470,7 +489,8 @@
     // shift.x = resolved_x[index] − result.x[index].
     // https://github.com/w3c/svgwg/issues/845
     if (resolve.HasX()) {
-      shift.SetX(resolve.x * scaling_factor - css_positions_[i].X());
+      shift.SetX(resolve.x * scaling_factor - css_positions_[i].X() -
+                 result_[i].text_length_shift_x);
       // Take into account of baseline-shift.
       if (!horizontal_)
         shift.SetX(shift.X() + css_positions_[i].X());
@@ -479,7 +499,8 @@
     // shift.y = resolved_y[index] − result.y[index].
     // https://github.com/w3c/svgwg/issues/845
     if (resolve.HasY()) {
-      shift.SetY(resolve.y * scaling_factor - css_positions_[i].Y());
+      shift.SetY(resolve.y * scaling_factor - css_positions_[i].Y() -
+                 result_[i].text_length_shift_y);
       // Take into account of baseline-shift.
       if (horizontal_)
         shift.SetY(shift.Y() + css_positions_[i].Y());
diff --git a/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.h
index 8c15647..670aae285 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/svg/ng_svg_text_layout_algorithm.h
@@ -67,6 +67,8 @@
     float baseline_shift = 0.0f;
     float inline_size = 0.0f;
     float length_adjust_scale = 1.0f;
+    float text_length_shift_x = 0.0f;
+    float text_length_shift_y = 0.0f;
     wtf_size_t item_index = WTF::kNotFound;
   };
   // This data member represents "result" defined in the specification, but it
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
index 604b79a..b7d3b59 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
@@ -521,11 +521,9 @@
        total_inner_border_spacing)
           .ClampNegativeToZero();
 
-  // Distribute min/max/percentage evenly between all cells.
+  // Distribute min/max evenly between all cells.
   LayoutUnit rounding_error_min_inline_size = colspan_cell_min_inline_size;
   LayoutUnit rounding_error_max_inline_size = colspan_cell_max_inline_size;
-  float rounding_error_percent =
-      colspan_cell.cell_inline_constraint.percent.value_or(0.0f);
 
   LayoutUnit new_min_size = LayoutUnit(colspan_cell_min_inline_size /
                                        static_cast<float>(effective_span));
@@ -536,7 +534,7 @@
     new_percent = *colspan_cell.cell_inline_constraint.percent / effective_span;
   }
 
-  NGTableTypes::Column* last_column;
+  NGTableTypes::Column* last_column = nullptr;
   for (NGTableTypes::Column* column = start_column; column < end_column;
        ++column) {
     if (column->is_mergeable)
@@ -544,8 +542,6 @@
     last_column = column;
     rounding_error_min_inline_size -= new_min_size;
     rounding_error_max_inline_size -= new_max_size;
-    if (new_percent)
-      rounding_error_percent -= *new_percent;
 
     if (!column->min_inline_size) {
       column->is_constrained |=
@@ -557,15 +553,16 @@
           colspan_cell.cell_inline_constraint.is_constrained;
       column->max_inline_size = new_max_size;
     }
-    if (!column->percent && new_percent)
-      column->percent = new_percent;
+    // Percentages only get distributed over auto columns.
+    if (!column->percent && !column->is_constrained && new_percent) {
+      column->percent = *new_percent;
+    }
   }
+  DCHECK(last_column);
   last_column->min_inline_size =
       *last_column->min_inline_size + rounding_error_min_inline_size;
   last_column->max_inline_size =
       *last_column->max_inline_size + rounding_error_max_inline_size;
-  if (new_percent)
-    last_column->percent = *last_column->percent + rounding_error_percent;
 }
 
 void DistributeColspanCellToColumnsAuto(
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc
index ccfbb10..6c12fe87 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -788,7 +788,7 @@
   VisibleSelectionInFlatTree selection =
       selected_frame->Selection().ComputeVisibleSelectionInFlatTree();
   EphemeralRangeInFlatTree selection_range(selection.Start(), selection.End());
-  selected_frame->GetTextFragmentSelectorGenerator()->UpdateSelection(
+  selected_frame->GetTextFragmentHandler()->MainFrameDidUpdateSelection(
       selection_range);
 }
 
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
index 8164011..c996b543 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
@@ -4,15 +4,26 @@
 
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h"
 
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
+#include "components/shared_highlighting/core/common/disabled_sites.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
 #include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
 
+namespace {
+bool PreemptiveGenerationEnabled() {
+  return base::FeatureList::IsEnabled(
+      shared_highlighting::kPreemptiveLinkToTextGeneration);
+}
+}  // namespace
+
 namespace blink {
 
 TextFragmentHandler::TextFragmentHandler(LocalFrame* main_frame)
@@ -28,17 +39,34 @@
           blink::TaskType::kInternalDefault));
 }
 
-TextFragmentSelectorGenerator*
-TextFragmentHandler::GetTextFragmentSelectorGenerator() {
-  return text_fragment_selector_generator_;
-}
-
 void TextFragmentHandler::Cancel() {
   GetTextFragmentSelectorGenerator()->Reset();
 }
 
 void TextFragmentHandler::RequestSelector(RequestSelectorCallback callback) {
-  GetTextFragmentSelectorGenerator()->RequestSelector(std::move(callback));
+  DCHECK(shared_highlighting::ShouldOfferLinkToText(
+      GetFrame()->GetDocument()->Url()));
+
+  if (PreemptiveGenerationEnabled()) {
+    GetTextFragmentSelectorGenerator()->RecordSelectorStateUma();
+
+    selector_requested_before_ready_ =
+        !preemptive_generation_result_.has_value();
+    response_callback_ = std::move(callback);
+
+    // If preemptive link generation is enabled, the generator would have
+    // already been invoked when the selection was updated in
+    // MainFrameDidUpdateSelection. If that generation finished simply respond
+    // with the result. Otherwise, the response callback is stored so that we
+    // reply on completion.
+    if (!selector_requested_before_ready_.value())
+      InvokeReplyCallback(preemptive_generation_result_.value());
+  } else {
+    DCHECK(!preemptive_generation_result_.has_value());
+    DCHECK(!response_callback_);
+    response_callback_ = std::move(callback);
+    StartGeneratingForCurrentSelection();
+  }
 }
 
 void TextFragmentHandler::GetExistingSelectors(
@@ -128,19 +156,103 @@
     PhysicalRect bounding_box(
         ComputeTextRect(finder->FirstMatch()->ToEphemeralRange()));
     rect_in_viewport =
-        GetTextFragmentSelectorGenerator()->GetFrame()->View()->FrameToViewport(
-            EnclosingIntRect(bounding_box));
+        GetFrame()->View()->FrameToViewport(EnclosingIntRect(bounding_box));
     break;
   }
 
   std::move(callback).Run(gfx::Rect(rect_in_viewport));
 }
 
+void TextFragmentHandler::DidFinishSelectorGeneration(
+    const TextFragmentSelector& selector) {
+  DCHECK(!preemptive_generation_result_.has_value());
+
+  if (response_callback_) {
+    InvokeReplyCallback(selector);
+  } else {
+    // If we don't have a callback yet, it's because we started generating
+    // preemptively. We'll store the result so that when the selector actually
+    // is requested we can simply use the stored result.
+    DCHECK(PreemptiveGenerationEnabled());
+    preemptive_generation_result_.emplace(selector);
+  }
+}
+
+void TextFragmentHandler::StartGeneratingForCurrentSelection() {
+  GetTextFragmentSelectorGenerator()->Generate(
+      *current_selection_range_,
+      WTF::Bind(&TextFragmentHandler::DidFinishSelectorGeneration,
+                WrapWeakPersistent(this)));
+}
+
+void TextFragmentHandler::RecordPreemptiveGenerationMetrics(
+    const TextFragmentSelector& selector) {
+  DCHECK(PreemptiveGenerationEnabled());
+  DCHECK(selector_requested_before_ready_.has_value());
+
+  bool success =
+      selector.Type() != TextFragmentSelector::SelectorType::kInvalid;
+
+  std::string uma_prefix = "SharedHighlights.LinkGenerated";
+  if (selector_requested_before_ready_.value()) {
+    uma_prefix = base::StrCat({uma_prefix, ".RequestedBeforeReady"});
+  } else {
+    uma_prefix = base::StrCat({uma_prefix, ".RequestedAfterReady"});
+  }
+  base::UmaHistogramBoolean(uma_prefix, success);
+
+  if (!success) {
+    absl::optional<shared_highlighting::LinkGenerationError> optional_error =
+        GetTextFragmentSelectorGenerator()->GetError();
+    shared_highlighting::LinkGenerationError error =
+        optional_error.has_value()
+            ? optional_error.value()
+            : shared_highlighting::LinkGenerationError::kUnknown;
+    base::UmaHistogramEnumeration(
+        "SharedHighlights.LinkGenerated.Error.Requested", error);
+  }
+}
+
+void TextFragmentHandler::MainFrameDidUpdateSelection(
+    const EphemeralRangeInFlatTree& selection_range) {
+  // TODO(bokan): Why can't we query this rather than trying to keep track of
+  // it?
+  current_selection_range_ = MakeGarbageCollected<RangeInFlatTree>(
+      selection_range.StartPosition(), selection_range.EndPosition());
+  if (PreemptiveGenerationEnabled() &&
+      shared_highlighting::ShouldOfferLinkToText(
+          GetFrame()->GetDocument()->Url())) {
+    preemptive_generation_result_.reset();
+    StartGeneratingForCurrentSelection();
+  }
+}
+
 void TextFragmentHandler::Trace(Visitor* visitor) const {
   visitor->Trace(text_fragment_selector_generator_);
+  visitor->Trace(current_selection_range_);
   visitor->Trace(selector_producer_);
 }
 
+void TextFragmentHandler::DidDetachDocumentOrFrame() {
+  // A frame (and thus, this object) can survive multiple documents. When a
+  // document is detached we need to explicitly clear the selection range so
+  // that we don't keep alive a stale range.
+  current_selection_range_ = nullptr;
+
+  // Clear out any state in the generator and cancel pending tasks so they
+  // don't run after frame detachment.
+  GetTextFragmentSelectorGenerator()->Reset();
+}
+
+void TextFragmentHandler::InvokeReplyCallback(
+    const TextFragmentSelector& selector) {
+  if (PreemptiveGenerationEnabled())
+    RecordPreemptiveGenerationMetrics(selector);
+
+  DCHECK(response_callback_);
+  std::move(response_callback_).Run(selector.ToString());
+}
+
 TextFragmentAnchor* TextFragmentHandler::GetTextFragmentAnchor() {
   FragmentAnchor* fragmentAnchor = GetTextFragmentSelectorGenerator()
                                        ->GetFrame()
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
index 9d6611b..aa346b00 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
@@ -12,53 +12,92 @@
 namespace blink {
 
 class LocalFrame;
+class RangeInFlatTree;
 class TextFragmentAnchor;
 
-// TextFragmentHandler is responsible for handling text fragment operations
-// on a LocalFrame. Generating text fragment selectors for a selection is
-// delegated to TextFragmentSelectorGenerator.
+// TextFragmentHandler is responsible for handling requests from the
+// browser-side link-to-text/shared-highlighting feature. It is responsible for
+// generating a text fragment URL based on the current selection as well as
+// collecting information about and modifying text fragments on the current
+// page. This class is registered on and owned by the main frame of a page.
 class CORE_EXPORT TextFragmentHandler final
     : public GarbageCollected<TextFragmentHandler>,
       public blink::mojom::blink::TextFragmentReceiver {
  public:
   explicit TextFragmentHandler(LocalFrame* main_frame);
 
-  void BindTextFragmentReceiver(
-      mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> producer);
-
-  // Cancel any pending selector requests.
-  void Cancel() override;
-
-  // Requests selector for current selection.
-  void RequestSelector(RequestSelectorCallback callback) override;
-
-  // Requests selectors for all existing highlights on the page.
-  void GetExistingSelectors(GetExistingSelectorsCallback callback) override;
-
-  // Remove all text fragments from the current frame.
-  void RemoveFragments() override;
-
   // Determine if |result| represents a click on an existing highlight.
   static bool IsOverTextFragment(HitTestResult result);
 
-  // Retrieves the text fragments matches from the fragment directive.
+  // mojom::blink::TextFragmentReceiver interface
+  void Cancel() override;
+  void RequestSelector(RequestSelectorCallback callback) override;
+  void GetExistingSelectors(GetExistingSelectorsCallback callback) override;
+  void RemoveFragments() override;
   void ExtractTextFragmentsMatches(
       ExtractTextFragmentsMatchesCallback callback) override;
-
-  // Request the bounding rectangle, relative to the viewport, of the first
-  // found match. It will accept an empty rectangle if no matches are found.
   void ExtractFirstFragmentRect(
       ExtractFirstFragmentRectCallback callback) override;
 
+  // Called by Blink when the selection in the main frame changes.
+  void MainFrameDidUpdateSelection(
+      const EphemeralRangeInFlatTree& selection_range);
+
+  void BindTextFragmentReceiver(
+      mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> producer);
+
   void Trace(Visitor*) const;
 
-  TextFragmentSelectorGenerator* GetTextFragmentSelectorGenerator();
+  TextFragmentSelectorGenerator* GetTextFragmentSelectorGenerator() {
+    return text_fragment_selector_generator_;
+  }
+
+  void DidDetachDocumentOrFrame();
 
  private:
+  // The callback passed to TextFragmentSelectorGenerator that will receive the
+  // result.
+  void DidFinishSelectorGeneration(const TextFragmentSelector& selector);
+
+  // This starts running the generator over the selection in
+  // |current_selection_range_|. The result will be returned by invoking
+  // DidFinishSelectorGeneration().
+  void StartGeneratingForCurrentSelection();
+
+  void RecordPreemptiveGenerationMetrics(const TextFragmentSelector& selector);
+
+  // Called to reply to the client's RequestSelector call with the result.
+  void InvokeReplyCallback(const TextFragmentSelector& selector);
+
+  TextFragmentAnchor* GetTextFragmentAnchor();
+
+  LocalFrame* GetFrame() {
+    return GetTextFragmentSelectorGenerator()->GetFrame();
+  }
+
   // Class responsible for generating text fragment selectors for the current
   // selection.
   Member<TextFragmentSelectorGenerator> text_fragment_selector_generator_;
 
+  // The Range of DOM currently selected by the user in the main frame. This
+  // class may preemptively start generating a selector based on this
+  // selection.
+  Member<RangeInFlatTree> current_selection_range_;
+
+  // The result of preemptively generating on selection changes will be stored
+  // in this member when completed. Used only in preemptive link generation
+  // mode.
+  absl::optional<TextFragmentSelector> preemptive_generation_result_;
+
+  // Reports whether |RequestSelector| was called before or after selector was
+  // ready. Used only in preemptive link generation mode.
+  absl::optional<bool> selector_requested_before_ready_;
+
+  // This will hold the reply callback to the RequestSelector mojo call. This
+  // will be invoked in InvokeReplyCallback to send the reply back to the
+  // browser.
+  RequestSelectorCallback response_callback_;
+
   // Used for communication between |TextFragmentHandler| in renderer
   // and |TextFragmentSelectorClientImpl| in browser.
   HeapMojoReceiver<blink::mojom::blink::TextFragmentReceiver,
@@ -66,8 +105,6 @@
       selector_producer_{this, nullptr};
 
   DISALLOW_COPY_AND_ASSIGN(TextFragmentHandler);
-
-  TextFragmentAnchor* GetTextFragmentAnchor();
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
index d7660cc..d247421 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
@@ -6,6 +6,8 @@
 
 #include <gtest/gtest.h>
 
+#include "base/feature_list.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -27,14 +29,25 @@
 
 using test::RunPendingTasks;
 
-class TextFragmentHandlerTest : public SimTest {
+class TextFragmentHandlerTest : public SimTest,
+                                public ::testing::WithParamInterface<bool> {
  public:
   void SetUp() override {
     SimTest::SetUp();
     WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
 
-    feature_list_.InitAndEnableFeature(
-        shared_highlighting::kSharedHighlightingV2);
+    std::vector<base::Feature> enabled;
+    std::vector<base::Feature> disabled;
+
+    enabled.push_back(shared_highlighting::kSharedHighlightingV2);
+
+    preemptive_generation_enabled_ = GetParam();
+    if (preemptive_generation_enabled_)
+      enabled.push_back(shared_highlighting::kPreemptiveLinkToTextGeneration);
+    else
+      disabled.push_back(shared_highlighting::kPreemptiveLinkToTextGeneration);
+
+    feature_list_.InitWithFeatures(enabled, disabled);
   }
 
   void RunAsyncMatchingTasks() {
@@ -45,6 +58,26 @@
     RunPendingTasks();
   }
 
+  String SelectThenRequestSelector(const Position& start, const Position& end) {
+    GetTextFragmentHandler().MainFrameDidUpdateSelection(
+        ToEphemeralRangeInFlatTree(EphemeralRange(start, end)));
+
+    bool callback_called = false;
+    String selector;
+    auto lambda = [](bool& callback_called, String& selector,
+                     const String& generated_selector) {
+      selector = generated_selector;
+      callback_called = true;
+    };
+    auto callback =
+        WTF::Bind(lambda, std::ref(callback_called), std::ref(selector));
+    GetTextFragmentHandler().RequestSelector(std::move(callback));
+    base::RunLoop().RunUntilIdle();
+
+    EXPECT_TRUE(callback_called);
+    return selector;
+  }
+
   Vector<String> ExtractTextFragmentsMatches() {
     bool callback_called = false;
     Vector<String> target_texts;
@@ -56,10 +89,7 @@
     auto callback =
         WTF::Bind(lambda, std::ref(callback_called), std::ref(target_texts));
 
-    GetDocument()
-        .GetFrame()
-        ->GetTextFragmentHandler()
-        ->ExtractTextFragmentsMatches(std::move(callback));
+    GetTextFragmentHandler().ExtractTextFragmentsMatches(std::move(callback));
 
     EXPECT_TRUE(callback_called);
     return target_texts;
@@ -76,10 +106,7 @@
     auto callback = WTF::Bind(lambda, std::ref(callback_called),
                               std::ref(text_fragment_rect));
 
-    GetDocument()
-        .GetFrame()
-        ->GetTextFragmentHandler()
-        ->ExtractFirstFragmentRect(std::move(callback));
+    GetTextFragmentHandler().ExtractFirstFragmentRect(std::move(callback));
 
     EXPECT_TRUE(callback_called);
     return text_fragment_rect;
@@ -102,11 +129,55 @@
         ->addForBinding(script_state, ahem, exception_state);
   }
 
- private:
+  void VerifyPreemptiveGenerationMetrics(bool success) {
+    if (!preemptive_generation_enabled_) {
+      histogram_tester_.ExpectTotalCount(
+          "SharedHighlights.LinkGenerated.Error.Requested", 0);
+      histogram_tester_.ExpectTotalCount(
+          "SharedHighlights.LinkGenerated.RequestedAfterReady", 0);
+      histogram_tester_.ExpectTotalCount(
+          "SharedHighlights.LinkGenerated.RequestedBeforeReady", 0);
+    } else {
+      EXPECT_EQ(
+          1u, histogram_tester_
+                      .GetAllSamples(
+                          "SharedHighlights.LinkGenerated.RequestedAfterReady")
+                      .size() +
+                  histogram_tester_
+                      .GetAllSamples(
+                          "SharedHighlights.LinkGenerated.RequestedBeforeReady")
+                      .size());
+
+      if (!success) {
+        histogram_tester_.ExpectTotalCount(
+            "SharedHighlights.LinkGenerated.Error.Requested", 1);
+      } else {
+        histogram_tester_.ExpectTotalCount(
+            "SharedHighlights.LinkGenerated.Error.Requested", 0);
+      }
+    }
+
+    // Check async task metrics.
+    EXPECT_LT(0u, histogram_tester_
+                      .GetAllSamples("SharedHighlights.AsyncTask.Iterations")
+                      .size());
+    EXPECT_LT(0u,
+              histogram_tester_
+                  .GetAllSamples("SharedHighlights.AsyncTask.SearchDuration")
+                  .size());
+  }
+
+  TextFragmentHandler& GetTextFragmentHandler() {
+    return *GetDocument().GetFrame()->GetTextFragmentHandler();
+  }
+
+ protected:
+  base::HistogramTester histogram_tester_;
   base::test::ScopedFeatureList feature_list_;
+  bool preemptive_generation_enabled_;
 };
 
-TEST_F(TextFragmentHandlerTest, RemoveTextFragments) {
+TEST_P(TextFragmentHandlerTest, RemoveTextFragments) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -140,7 +211,7 @@
 
   EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
 
-  GetDocument().GetFrame()->GetTextFragmentHandler()->RemoveFragments();
+  GetTextFragmentHandler().RemoveFragments();
 
   EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
 
@@ -148,7 +219,7 @@
   EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
 }
 
-TEST_F(TextFragmentHandlerTest,
+TEST_P(TextFragmentHandlerTest,
        ExtractTextFragmentWithWithMultipleTextFragments) {
   SimRequest request(
       "https://example.com/"
@@ -188,7 +259,7 @@
   EXPECT_EQ("more text", target_texts[1]);
 }
 
-TEST_F(TextFragmentHandlerTest, ExtractTextFragmentWithNoMatch) {
+TEST_P(TextFragmentHandlerTest, ExtractTextFragmentWithNoMatch) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=not%20on%20the%20page",
@@ -224,7 +295,7 @@
   EXPECT_EQ(0u, target_texts.size());
 }
 
-TEST_F(TextFragmentHandlerTest, ExtractTextFragmentWithRange) {
+TEST_P(TextFragmentHandlerTest, ExtractTextFragmentWithRange) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=This,text",
@@ -261,7 +332,7 @@
   EXPECT_EQ("This is a test page, with some more text", target_texts[0]);
 }
 
-TEST_F(TextFragmentHandlerTest, ExtractTextFragmentWithRangeAndContext) {
+TEST_P(TextFragmentHandlerTest, ExtractTextFragmentWithRangeAndContext) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=this,is&text=a-,test,page&text=with,some,-content&"
@@ -292,7 +363,7 @@
   EXPECT_EQ("nothing at", target_texts[3]);
 }
 
-TEST_F(TextFragmentHandlerTest, ExtractFirstTextFragmentRect) {
+TEST_P(TextFragmentHandlerTest, ExtractFirstTextFragmentRect) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=This,page",
@@ -330,7 +401,7 @@
   EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString());
 }
 
-TEST_F(TextFragmentHandlerTest, ExtractFirstTextFragmentRectScroll) {
+TEST_P(TextFragmentHandlerTest, ExtractFirstTextFragmentRectScroll) {
   // Android settings to correctly extract the rect when the page is loaded
   // zoomed in
   WebView().GetPage()->GetSettings().SetViewportEnabled(true);
@@ -379,7 +450,7 @@
   EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString());
 }
 
-TEST_F(TextFragmentHandlerTest, ExtractFirstTextFragmentRectMultipleHighlight) {
+TEST_P(TextFragmentHandlerTest, ExtractFirstTextFragmentRectMultipleHighlight) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -428,7 +499,7 @@
   EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString());
 }
 
-TEST_F(TextFragmentHandlerTest,
+TEST_P(TextFragmentHandlerTest,
        ExtractFirstTextFragmentRectMultipleHighlightWithNoFoundText) {
   SimRequest request(
       "https://example.com/"
@@ -477,7 +548,7 @@
   EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString());
 }
 
-TEST_F(TextFragmentHandlerTest, RejectExtractFirstTextFragmentRect) {
+TEST_P(TextFragmentHandlerTest, RejectExtractFirstTextFragmentRect) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=not%20on%20the%20page",
@@ -515,6 +586,171 @@
   EXPECT_TRUE(text_fragment_rect.IsEmpty());
 }
 
+// Checks that the selector is preemptively generated.
+TEST_P(TextFragmentHandlerTest, CheckPreemptiveGeneration) {
+  if (!preemptive_generation_enabled_)
+    return;
+
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <p id='first'>First paragraph</p>
+    )HTML");
+
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& selected_start = Position(first_paragraph, 0);
+  const auto& selected_end = Position(first_paragraph, 5);
+  ASSERT_EQ("First", PlainText(EphemeralRange(selected_start, selected_end)));
+
+  GetTextFragmentHandler().MainFrameDidUpdateSelection(
+      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 1);
+  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 0);
+}
+
+// When URL is blocklisted, the selector shouldn't be preemptively generated.
+TEST_P(TextFragmentHandlerTest, CheckNoPreemptiveGenerationBlocklist) {
+  if (!preemptive_generation_enabled_)
+    return;
+
+  SimRequest request("https://instagram.com/test.html", "text/html");
+  LoadURL("https://instagram.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <p id='first'>First paragraph</p>
+    )HTML");
+
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& selected_start = Position(first_paragraph, 0);
+  const auto& selected_end = Position(first_paragraph, 5);
+  ASSERT_EQ("First", PlainText(EphemeralRange(selected_start, selected_end)));
+
+  GetTextFragmentHandler().MainFrameDidUpdateSelection(
+      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 0);
+  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 0);
+}
+
+// Check that selector is not generated for editable text.
+TEST_P(TextFragmentHandlerTest, CheckNoPreemptiveGenerationEditable) {
+  if (!preemptive_generation_enabled_)
+    return;
+
+  SimRequest request("https://instagram.com/test.html", "text/html");
+  LoadURL("https://instagram.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <input type="text" id="input" value="default text in input">
+    )HTML");
+
+  Node* input_text =
+      FlatTreeTraversal::Next(*GetDocument().getElementById("input"))
+          ->firstChild();
+  const auto& selected_start = Position(input_text, 0);
+  const auto& selected_end = Position(input_text, 12);
+  ASSERT_EQ("default text",
+            PlainText(EphemeralRange(selected_start, selected_end)));
+
+  GetTextFragmentHandler().MainFrameDidUpdateSelection(
+      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 0);
+  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 0);
+}
+
+// TODO(crbug.com/1192047): Update the test to better reflect the real repro
+// steps. Test case for crash in crbug.com/1190137. When selector is requested
+// after callback is set and unused.
+TEST_P(TextFragmentHandlerTest, SecondGenerationCrash) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+  <p id='p'>First paragraph text</p>
+  )HTML");
+  GetDocument().UpdateStyleAndLayoutTree();
+  Node* p = GetDocument().getElementById("p");
+  const auto& start = Position(p->lastChild(), 0);
+  const auto& end = Position(p->lastChild(), 15);
+  ASSERT_EQ("First paragraph", PlainText(EphemeralRange(start, end)));
+
+  auto callback = WTF::Bind([](const TextFragmentSelector& selector) {});
+  GetDocument()
+      .GetFrame()
+      ->GetTextFragmentHandler()
+      ->GetTextFragmentSelectorGenerator()
+      ->SetCallbackForTesting(std::move(callback));
+
+  // This shouldn't crash.
+  GetTextFragmentHandler().MainFrameDidUpdateSelection(
+      ToEphemeralRangeInFlatTree(EphemeralRange(start, end)));
+  base::RunLoop().RunUntilIdle();
+}
+
+// Verifies metrics for preemptive generation are correctly recorded when the
+// selector is successfully generated.
+TEST_P(TextFragmentHandlerTest, CheckMetrics_Success) {
+  base::test::ScopedFeatureList feature_list;
+  // Basic exact selector case.
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div>Test page</div>
+    <p id='first'>First paragraph text that is longer than 20 chars</p>
+    <p id='second'>Second paragraph text</p>
+  )HTML");
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& selected_start = Position(first_paragraph, 0);
+  const auto& selected_end = Position(first_paragraph, 28);
+  ASSERT_EQ("First paragraph text that is",
+            PlainText(EphemeralRange(selected_start, selected_end)));
+
+  String selector = SelectThenRequestSelector(selected_start, selected_end);
+  EXPECT_EQ(selector, "First%20paragraph%20text%20that%20is");
+  VerifyPreemptiveGenerationMetrics(true);
+}
+
+// Verifies metrics for preemptive generation are correctly recorded when the
+// selector request fails, in this case, because the context limit is reached.
+TEST_P(TextFragmentHandlerTest, CheckMetrics_Failure) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div>Test page</div>
+    <p id='first'>First paragraph prefix one two three four five six seven
+     eight nine ten to not unique snippet of text followed by suffix</p>
+    <p id='second'>Second paragraph prefix one two three four five six seven
+     eight nine ten to not unique snippet of text followed by suffix</p>
+  )HTML");
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& selected_start = Position(first_paragraph, 80);
+  const auto& selected_end = Position(first_paragraph, 106);
+  ASSERT_EQ("not unique snippet of text",
+            PlainText(EphemeralRange(selected_start, selected_end)));
+  String selector = SelectThenRequestSelector(selected_start, selected_end);
+  EXPECT_EQ(selector, "");
+  VerifyPreemptiveGenerationMetrics(false);
+}
+
+struct PreemptiveLinkGenerationTestPassToString {
+  std::string operator()(const testing::TestParamInfo<bool> b) const {
+    return b.param ? "Preemptive" : "NonPreemptive";
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         TextFragmentHandlerTest,
+                         ::testing::Bool(),
+                         PreemptiveLinkGenerationTestPassToString());
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
index 993fd606..1d7a14a 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
@@ -6,9 +6,7 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/strcat.h"
 #include "base/time/default_tick_clock.h"
-#include "components/shared_highlighting/core/common/disabled_sites.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_metrics.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
@@ -16,6 +14,7 @@
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
+#include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h"
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h"
@@ -192,46 +191,15 @@
   DCHECK(main_frame->IsMainFrame());
 }
 
-void TextFragmentSelectorGenerator::UpdateSelection(
-    const EphemeralRangeInFlatTree& selection_range) {
-  selection_range_ = MakeGarbageCollected<Range>(
-      selection_range.GetDocument(),
-      ToPositionInDOMTree(selection_range.StartPosition()),
-      ToPositionInDOMTree(selection_range.EndPosition()));
-  if (base::FeatureList::IsEnabled(
-          shared_highlighting::kPreemptiveLinkToTextGeneration) &&
-      shared_highlighting::ShouldOfferLinkToText(
-          frame_->GetDocument()->Url())) {
-    Reset();
-    GenerateSelector();
-  }
-}
-
-void TextFragmentSelectorGenerator::RequestSelector(
-    RequestSelectorCallback callback) {
+void TextFragmentSelectorGenerator::Generate(const RangeInFlatTree& range,
+                                             GenerateCallback callback) {
   DCHECK(callback);
-  if (!base::FeatureList::IsEnabled(
-          shared_highlighting::kPreemptiveLinkToTextGeneration)) {
-    Reset();
-    pending_generate_selector_callback_ = std::move(callback);
-    GenerateSelector();
-  } else {
-    base::UmaHistogramEnumeration(
-        "SharedHighlights.LinkGenerated.StateAtRequest", state_);
-    pending_generate_selector_callback_ = std::move(callback);
-    DCHECK_NE(state_, kNotStarted);
-    if (state_ == kFailure || state_ == kSuccess) {
-      selector_requested_before_ready_ = false;
-      if (state_ == kFailure) {
-        NotifyClientSelectorReady(
-            TextFragmentSelector(TextFragmentSelector::SelectorType::kInvalid));
-      } else {
-        NotifyClientSelectorReady(*selector_);
-      }
-      return;
-    }
-    selector_requested_before_ready_ = true;
-  }
+  Reset();
+  range_ = MakeGarbageCollected<RangeInFlatTree>(range.StartPosition(),
+                                                 range.EndPosition());
+  pending_generate_selector_callback_ = std::move(callback);
+
+  StartGeneration();
 }
 
 void TextFragmentSelectorGenerator::Reset() {
@@ -250,36 +218,28 @@
   num_range_words_ = 0;
   iteration_ = 0;
   selector_ = nullptr;
-  selector_requested_before_ready_.reset();
+  range_ = nullptr;
   pending_generate_selector_callback_.Reset();
 }
 
-void TextFragmentSelectorGenerator::ClearSelection() {
-  if (selection_range_) {
-    selection_range_->Dispose();
-    selection_range_ = nullptr;
-  }
-}
-
-void TextFragmentSelectorGenerator::Detach() {
-  Reset();
-  frame_ = nullptr;
-}
-
 void TextFragmentSelectorGenerator::Trace(Visitor* visitor) const {
   visitor->Trace(frame_);
-  visitor->Trace(selection_range_);
+  visitor->Trace(range_);
   visitor->Trace(finder_);
 }
 
+void TextFragmentSelectorGenerator::RecordSelectorStateUma() const {
+  base::UmaHistogramEnumeration("SharedHighlights.LinkGenerated.StateAtRequest",
+                                state_);
+}
+
 void TextFragmentSelectorGenerator::DidFindMatch(
     const EphemeralRangeInFlatTree& match,
     const TextFragmentAnchorMetrics::Match match_metrics,
     bool is_unique) {
-  if (is_unique && PlainText(match).StripWhiteSpace().length() ==
-                       PlainText(EphemeralRangeInFlatTree(selection_range_))
-                           .StripWhiteSpace()
-                           .length()) {
+  if (is_unique &&
+      PlainText(match).StripWhiteSpace().length() ==
+          PlainText(range_->ToEphemeralRange()).StripWhiteSpace().length()) {
     state_ = kSuccess;
     ResolveSelectorState();
   } else {
@@ -299,10 +259,10 @@
 }
 
 void TextFragmentSelectorGenerator::AdjustSelection() {
-  if (!selection_range_)
+  if (!range_)
     return;
 
-  EphemeralRangeInFlatTree ephemeral_range(selection_range_);
+  EphemeralRangeInFlatTree ephemeral_range = range_->ToEphemeralRange();
   Node* start_container =
       ephemeral_range.StartPosition().ComputeContainerNode();
   Node* end_container = ephemeral_range.EndPosition().ComputeContainerNode();
@@ -372,21 +332,20 @@
       corrected_end != end_container ||
       corrected_end_offset !=
           ephemeral_range.EndPosition().ComputeOffsetInContainerNode()) {
-    selection_range_ = MakeGarbageCollected<Range>(
-        selection_range_->OwnerDocument(),
-        Position(corrected_start, corrected_start_offset),
-        Position(corrected_end, corrected_end_offset));
+    range_ = MakeGarbageCollected<RangeInFlatTree>(
+        PositionInFlatTree(corrected_start, corrected_start_offset),
+        PositionInFlatTree(corrected_end, corrected_end_offset));
   }
 }
 
-void TextFragmentSelectorGenerator::GenerateSelector() {
-  DCHECK(selection_range_);
+void TextFragmentSelectorGenerator::StartGeneration() {
+  DCHECK(range_);
 
-  selection_range_->OwnerDocument().UpdateStyleAndLayout(
+  range_->StartPosition().GetDocument()->UpdateStyleAndLayout(
       DocumentUpdateReason::kFindInPage);
 
   // Shouldn't continue if selection is empty.
-  EphemeralRangeInFlatTree ephemeral_range(selection_range_);
+  EphemeralRangeInFlatTree ephemeral_range = range_->ToEphemeralRange();
   String selected_text = PlainText(ephemeral_range).StripWhiteSpace();
   if (selected_text.IsEmpty()) {
     state_ = kFailure;
@@ -396,9 +355,8 @@
   }
 
   AdjustSelection();
-  UMA_HISTOGRAM_COUNTS_1000(
-      "SharedHighlights.LinkGenerated.SelectionLength",
-      PlainText(EphemeralRange(selection_range_)).length());
+  UMA_HISTOGRAM_COUNTS_1000("SharedHighlights.LinkGenerated.SelectionLength",
+                            PlainText(range_->ToEphemeralRange()).length());
   state_ = kNeedsNewCandidate;
   GenerateSelectorCandidate();
 }
@@ -504,7 +462,7 @@
 void TextFragmentSelectorGenerator::GenerateExactSelector() {
   DCHECK_EQ(kExact, step_);
   DCHECK_EQ(kNeedsNewCandidate, state_);
-  EphemeralRangeInFlatTree ephemeral_range(selection_range_);
+  EphemeralRangeInFlatTree ephemeral_range = range_->ToEphemeralRange();
 
   // If not in same block, should use ranges.
   if (!TextFragmentFinder::IsInSameUninterruptedBlock(
@@ -543,7 +501,7 @@
   // Initialize range start/end and word min count, if needed.
   if (max_available_range_start_.IsEmpty() &&
       max_available_range_end_.IsEmpty()) {
-    EphemeralRangeInFlatTree ephemeral_range(selection_range_);
+    EphemeralRangeInFlatTree ephemeral_range = range_->ToEphemeralRange();
 
     // If selection starts and ends in the same block, then split selected text
     // roughly in the middle.
@@ -571,9 +529,9 @@
       // If not the same node, then we use first and last block of the selection
       // range.
       max_available_range_start_ =
-          GetNextTextBlock(selection_range_->StartPosition());
+          GetNextTextBlock(ToPositionInDOMTree(range_->StartPosition()));
       max_available_range_end_ =
-          GetPreviousTextBlock(selection_range_->EndPosition());
+          GetPreviousTextBlock(ToPositionInDOMTree(range_->EndPosition()));
     }
 
     // Use at least 3 words from both sides for more robust link to text.
@@ -611,8 +569,9 @@
   // Try initiating properties necessary for calculating prefix and suffix.
   if (max_available_prefix_.IsEmpty() && max_available_suffix_.IsEmpty()) {
     max_available_prefix_ =
-        GetPreviousTextBlock(selection_range_->StartPosition());
-    max_available_suffix_ = GetNextTextBlock(selection_range_->EndPosition());
+        GetPreviousTextBlock(ToPositionInDOMTree(range_->StartPosition()));
+    max_available_suffix_ =
+        GetNextTextBlock(ToPositionInDOMTree(range_->EndPosition()));
 
     // Use at least 3 words from both sides for more robust link to text.
     num_context_words_ = kMinWordCount_;
@@ -679,29 +638,6 @@
   }
 }
 
-void TextFragmentSelectorGenerator::RecordPreemptiveGenerationMetrics(
-    const TextFragmentSelector& selector) {
-  DCHECK(selector_requested_before_ready_.has_value());
-
-  bool success =
-      selector.Type() != TextFragmentSelector::SelectorType::kInvalid;
-
-  std::string uma_prefix = "SharedHighlights.LinkGenerated";
-  if (selector_requested_before_ready_.value()) {
-    uma_prefix = base::StrCat({uma_prefix, ".RequestedBeforeReady"});
-  } else {
-    uma_prefix = base::StrCat({uma_prefix, ".RequestedAfterReady"});
-  }
-  base::UmaHistogramBoolean(uma_prefix, success);
-
-  if (!success) {
-    LinkGenerationError error =
-        error_.has_value() ? error_.value() : LinkGenerationError::kUnknown;
-    base::UmaHistogramEnumeration(
-        "SharedHighlights.LinkGenerated.Error.Requested", error);
-  }
-}
-
 void TextFragmentSelectorGenerator::OnSelectorReady(
     const TextFragmentSelector& selector) {
   // Check that frame is not deattched and generator is still valid.
@@ -716,10 +652,7 @@
 void TextFragmentSelectorGenerator::NotifyClientSelectorReady(
     const TextFragmentSelector& selector) {
   DCHECK(pending_generate_selector_callback_);
-  if (base::FeatureList::IsEnabled(
-          shared_highlighting::kPreemptiveLinkToTextGeneration))
-    RecordPreemptiveGenerationMetrics(selector);
-  std::move(pending_generate_selector_callback_).Run(selector.ToString());
+  std::move(pending_generate_selector_callback_).Run(selector);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
index 02f5435..8762de09 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
@@ -15,12 +15,13 @@
 namespace blink {
 
 class LocalFrame;
+class RangeInFlatTree;
 class TextFragmentSelector;
 
-// TextFragmentSelectorGenerator is used to generate a text directive selector
-// string, given a range of DOM in a document. The "selector string" is the
-// portion of a "scroll-to-text" URL that follows `#:~:text=`. For more
-// details, see:
+// TextFragmentSelectorGenerator is used to generate a TextFragmentSelector,
+// given a range of DOM in a document. The TextFragmentSelector provides the
+// necessary portions of a text fragment URL such that it scrolls to the given
+// range when navigated. For more details, see:
 // https://github.com/WICG/scroll-to-text-fragment#proposed-solution.
 //
 // TextFragmentSelectorGenerator works by starting with a candidate selector
@@ -31,21 +32,16 @@
 class CORE_EXPORT TextFragmentSelectorGenerator final
     : public GarbageCollected<TextFragmentSelectorGenerator>,
       public TextFragmentFinder::Client {
-  using RequestSelectorCallback = base::OnceCallback<void(const WTF::String&)>;
+  using GenerateCallback =
+      base::OnceCallback<void(const TextFragmentSelector&)>;
 
  public:
   explicit TextFragmentSelectorGenerator(LocalFrame* main_frame);
 
-  // Sets range for which a selector will be generated when RequestSelector()
-  // is called.
-  void UpdateSelection(const EphemeralRangeInFlatTree& selection_range);
-
-  // Requests selector for current selection range specified in
-  // UpdateSelection. Will be generated asynchronously and returned as a string
-  // in the callback. The returned string is the result of
-  // TextFragmentSelector::ToString(), i.e. the part that follows "#:~:text="
-  // in the URL.
-  void RequestSelector(RequestSelectorCallback callback);
+  // Requests a TextFragmentSelector be generated for the selection of DOM
+  // specified by |range|. Will be generated asynchronously and returned by
+  // invoking |callback|.
+  void Generate(const RangeInFlatTree& range, GenerateCallback callback);
 
   // Resets generator state to initial values and cancels any existing async
   // tasks.
@@ -58,20 +54,24 @@
   String GetNextTextBlockForTesting(const Position& position) {
     return GetNextTextBlock(position);
   }
-  void SetCallbackForTesting(RequestSelectorCallback callback) {
+  void SetCallbackForTesting(GenerateCallback callback) {
     pending_generate_selector_callback_ = std::move(callback);
   }
 
-  // Called when the frame is detached. Releases members if necessary.
-  void ClearSelection();
-
-  // Called when the document is detached.
-  void Detach();
-
   void Trace(Visitor*) const;
 
+  // Temporary diagnostic metric recorded to help explain discrepancies in
+  // other metrics.
+  void RecordSelectorStateUma() const;
+
   LocalFrame* GetFrame() { return frame_; }
 
+  // If generation fails, returns the reason that generation failed. If
+  // generation hasn't finished, or was successful, returns an empty optional.
+  absl::optional<shared_highlighting::LinkGenerationError> GetError() {
+    return error_;
+  }
+
  private:
   // Used for determining the next step of selector generation.
   enum GenerationStep { kExact, kRange, kContext };
@@ -110,7 +110,7 @@
   void AdjustSelection();
 
   // Generates selector for current selection.
-  void GenerateSelector();
+  void StartGeneration();
 
   void GenerateSelectorCandidate();
 
@@ -130,27 +130,25 @@
   void ExtendContext();
 
   void RecordAllMetrics(const TextFragmentSelector& selector);
-  void RecordPreemptiveGenerationMetrics(const TextFragmentSelector& selector);
 
   // Called when selector generation is complete.
   void OnSelectorReady(const TextFragmentSelector& selector);
 
-  // Called to notify clients of the result of |RequestSelector|.
+  // Called to notify clients of the result of |Generate|.
   void NotifyClientSelectorReady(const TextFragmentSelector& selector);
 
   Member<LocalFrame> frame_;
-  Member<Range> selection_range_;
+
+  // This is the Range for which we're generating a selector.
+  Member<RangeInFlatTree> range_;
+
   std::unique_ptr<TextFragmentSelector> selector_;
 
-  RequestSelectorCallback pending_generate_selector_callback_;
+  GenerateCallback pending_generate_selector_callback_;
 
   GenerationStep step_ = kExact;
   SelectorState state_ = kNeedsNewCandidate;
 
-  // Used when preemptive link generation is enabled to report
-  // whether |RequestSelector| was called before or after selector was ready.
-  absl::optional<bool> selector_requested_before_ready_;
-
   absl::optional<shared_highlighting::LinkGenerationError> error_;
 
   // Fields used for keeping track of context.
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
index 1168cb9..7faa6a4 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
@@ -9,7 +9,6 @@
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_metrics.h"
 #include "components/ukm/test_ukm_recorder.h"
@@ -20,6 +19,7 @@
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h"
 #include "third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -33,21 +33,11 @@
 const char kErrorUkmMetric[] = "Error";
 }  // namespace
 
-class TextFragmentSelectorGeneratorTest
-    : public SimTest,
-      public ::testing::WithParamInterface<bool> {
+class TextFragmentSelectorGeneratorTest : public SimTest {
  public:
   void SetUp() override {
     SimTest::SetUp();
     WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
-    preemptive_generation_enabled_ = GetParam();
-    if (preemptive_generation_enabled_) {
-      feature_list_.InitAndEnableFeature(
-          shared_highlighting::kPreemptiveLinkToTextGeneration);
-    } else {
-      feature_list_.InitAndDisableFeature(
-          shared_highlighting::kPreemptiveLinkToTextGeneration);
-    }
   }
 
   void VerifySelector(Position selected_start,
@@ -95,67 +85,32 @@
 
   String GenerateSelector(Position selected_start, Position selected_end) {
     generate_call_count_++;
-    GetDocument()
-        .GetFrame()
-        ->GetTextFragmentSelectorGenerator()
-        ->UpdateSelection(ToEphemeralRangeInFlatTree(
-            EphemeralRange(selected_start, selected_end)));
 
     bool callback_called = false;
     String selector;
     auto lambda = [](bool& callback_called, String& selector,
-                     const String& generated_selector) {
-      selector = generated_selector;
+                     const TextFragmentSelector& generated_selector) {
+      selector = generated_selector.ToString();
       callback_called = true;
     };
     auto callback =
         WTF::Bind(lambda, std::ref(callback_called), std::ref(selector));
-    GetDocument()
-        .GetFrame()
-        ->GetTextFragmentSelectorGenerator()
-        ->RequestSelector(std::move(callback));
+    GetTextFragmentSelectorGenerator()->Generate(
+        *MakeGarbageCollected<RangeInFlatTree>(
+            ToPositionInFlatTree(selected_start),
+            ToPositionInFlatTree(selected_end)),
+        std::move(callback));
     base::RunLoop().RunUntilIdle();
 
     EXPECT_TRUE(callback_called);
     return selector;
   }
 
-  void VerifyPreemptiveGenerationMetrics(bool success) {
-    if (!preemptive_generation_enabled_) {
-      histogram_tester_.ExpectTotalCount(
-          "SharedHighlights.LinkGenerated.Error.Requested", 0);
-      histogram_tester_.ExpectTotalCount(
-          "SharedHighlights.LinkGenerated.RequestedAfterReady", 0);
-      histogram_tester_.ExpectTotalCount(
-          "SharedHighlights.LinkGenerated.RequestedBeforeReady", 0);
-    } else {
-      EXPECT_EQ(
-          1u, histogram_tester_
-                      .GetAllSamples(
-                          "SharedHighlights.LinkGenerated.RequestedAfterReady")
-                      .size() +
-                  histogram_tester_
-                      .GetAllSamples(
-                          "SharedHighlights.LinkGenerated.RequestedBeforeReady")
-                      .size());
-
-      if (!success) {
-        histogram_tester_.ExpectTotalCount(
-            "SharedHighlights.LinkGenerated.Error.Requested", 1);
-      } else {
-        histogram_tester_.ExpectTotalCount(
-            "SharedHighlights.LinkGenerated.Error.Requested", 0);
-      }
-    }
-
-    // Check async task metrics.
-    EXPECT_LT(0u, histogram_tester_
-                      .GetAllSamples("SharedHighlights.AsyncTask.Iterations")
-                      .size());
-    EXPECT_LT(0u,
-              histogram_tester_
-                  .GetAllSamples("SharedHighlights.AsyncTask.SearchDuration")
-                  .size());
+  TextFragmentSelectorGenerator* GetTextFragmentSelectorGenerator() {
+    return GetDocument()
+        .GetFrame()
+        ->GetTextFragmentHandler()
+        ->GetTextFragmentSelectorGenerator();
   }
 
  protected:
@@ -166,91 +121,10 @@
   base::HistogramTester histogram_tester_;
   ScopedFakeUkmRecorder scoped_ukm_recorder_;
   int generate_call_count_ = 0;
-  bool preemptive_generation_enabled_;
-  base::test::ScopedFeatureList feature_list_;
 };
 
-// Checks that the selector is preemptively generated.
-TEST_P(TextFragmentSelectorGeneratorTest, CheckPreemptiveGeneration) {
-  if (!preemptive_generation_enabled_)
-    return;
-
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <p id='first'>First paragraph</p>
-    )HTML");
-
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& selected_start = Position(first_paragraph, 0);
-  const auto& selected_end = Position(first_paragraph, 5);
-  ASSERT_EQ("First", PlainText(EphemeralRange(selected_start, selected_end)));
-
-  GetDocument().GetFrame()->GetTextFragmentSelectorGenerator()->UpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
-  base::RunLoop().RunUntilIdle();
-
-  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 1);
-  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 0);
-}
-
-// When URL is blocklisted, the selector shouldn't be preemptively generated.
-TEST_P(TextFragmentSelectorGeneratorTest,
-       CheckNoPreemptiveGenerationBlocklist) {
-  if (!preemptive_generation_enabled_)
-    return;
-
-  SimRequest request("https://instagram.com/test.html", "text/html");
-  LoadURL("https://instagram.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <p id='first'>First paragraph</p>
-    )HTML");
-
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& selected_start = Position(first_paragraph, 0);
-  const auto& selected_end = Position(first_paragraph, 5);
-  ASSERT_EQ("First", PlainText(EphemeralRange(selected_start, selected_end)));
-
-  GetDocument().GetFrame()->GetTextFragmentSelectorGenerator()->UpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
-  base::RunLoop().RunUntilIdle();
-
-  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 0);
-  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 0);
-}
-
-// Check that selector is not generated for editable text.
-TEST_P(TextFragmentSelectorGeneratorTest, CheckNoPreemptiveGenerationEditable) {
-  if (!preemptive_generation_enabled_)
-    return;
-
-  SimRequest request("https://instagram.com/test.html", "text/html");
-  LoadURL("https://instagram.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <input type="text" id="input" value="default text in input">
-    )HTML");
-
-  Node* input_text =
-      FlatTreeTraversal::Next(*GetDocument().getElementById("input"))
-          ->firstChild();
-  const auto& selected_start = Position(input_text, 0);
-  const auto& selected_end = Position(input_text, 12);
-  ASSERT_EQ("default text",
-            PlainText(EphemeralRange(selected_start, selected_end)));
-
-  GetDocument().GetFrame()->GetTextFragmentSelectorGenerator()->UpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
-  base::RunLoop().RunUntilIdle();
-
-  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 0);
-  histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 0);
-}
-
 // Basic exact selector case.
-TEST_P(TextFragmentSelectorGeneratorTest, EmptySelection) {
+TEST_F(TextFragmentSelectorGeneratorTest, EmptySelection) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -267,7 +141,7 @@
 }
 
 // Basic exact selector case.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -287,7 +161,7 @@
 }
 
 // Exact selector test where selection contains nested <i> node.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextWithNestedTextNodes) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextWithNestedTextNodes) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -308,7 +182,7 @@
 }
 
 // Exact selector test where selection contains multiple spaces.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextWithExtraSpace) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextWithExtraSpace) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -329,7 +203,7 @@
 
 // Exact selector where selection is too short, in which case context is
 // required.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_TooShortNeedsContext) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -351,7 +225,7 @@
 
 // Exact selector with context test. Case when only one word for prefix and
 // suffix is enough to disambiguate the selection.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_WithOneWordContext) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -373,7 +247,7 @@
 
 // Exact selector with context test. Case when multiple words for prefix and
 // suffix is necessary to disambiguate the selection.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_MultipleWordContext) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -397,7 +271,7 @@
 // Exact selector with context test. Case when multiple words for prefix and
 // suffix is necessary to disambiguate the selection and prefix and suffix
 // contain extra space.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_MultipleWordContext_ExtraSpace) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -421,7 +295,7 @@
 // Exact selector with context test. Case when available prefix for all the
 // occurrences of selected text is the same. In this case suffix should be
 // extended until unique selector is found.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -444,7 +318,7 @@
 // Exact selector with context test. Case when available suffix for all the
 // occurrences of selected text is the same. In this case prefix should be
 // extended until unique selector is found.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_SameSuffix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SameSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -467,7 +341,7 @@
 // Exact selector with context test. Case when available prefix and suffix for
 // all the occurrences of selected text are the same. In this case generation
 // should be unsuccessful.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefixSuffix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefixSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -489,7 +363,7 @@
 // Exact selector with context test. Case when available prefix and suffix for
 // all the occurrences of selected text are the same for the first 10 words. In
 // this case generation should be unsuccessful.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_SimilarLongPreffixSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -512,7 +386,7 @@
 }
 
 // Exact selector with context test. Case when no prefix is available.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoPrefix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoPrefix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -531,7 +405,7 @@
 }
 
 // Exact selector with context test. Case when no suffix is available.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoSuffix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -553,7 +427,7 @@
 
 // Exact selector with context test. Case when available prefix is the
 // preceding block.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_PrevNodePrefix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_PrevNodePrefix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -574,7 +448,7 @@
 
 // Exact selector with context test. Case when available prefix is the
 // preceding block, which is a text node.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_PrevTextNodePrefix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -597,7 +471,7 @@
 
 // Exact selector with context test. Case when available suffix is the next
 // block.
-TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_NextNodeSuffix) {
+TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NextNodeSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -619,7 +493,7 @@
 
 // Exact selector with context test. Case when available suffix is the next
 // block, which is a text node.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        ExactTextSelector_NexttextNodeSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -640,7 +514,7 @@
                  "First%20paragraph%20with-,not%20unique%20snippet,-text");
 }
 
-TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector) {
+TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -662,7 +536,7 @@
 
 // It should be more than 300 characters selected from the same node so that
 // ranges are used.
-TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -691,7 +565,7 @@
 
 // It should be more than 300 characters selected from the same node so that
 // ranges are used.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        RangeSelector_SameNode_MultipleSelections) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -741,7 +615,7 @@
 
 // When using all the selected text for the range is not enough for unique
 // match, context should be added.
-TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_RangeNotUnique) {
+TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_RangeNotUnique) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -763,7 +637,7 @@
 
 // When using all the selected text for the range is not enough for unique
 // match, context should be added, but only prefxi and no suffix is available.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        RangeSelector_RangeNotUnique_NoSuffix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -786,7 +660,7 @@
 // When no range end is available it should return empty selector.
 // There is no range end available because there is no word break in the second
 // half of the selection.
-TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_NoRangeEnd) {
+TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_NoRangeEnd) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -812,7 +686,7 @@
 }
 
 // Selection should be autocompleted to contain full words.
-TEST_P(TextFragmentSelectorGeneratorTest, WordLimit) {
+TEST_F(TextFragmentSelectorGeneratorTest, WordLimit) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -832,7 +706,7 @@
 
 // Selection should be autocompleted to contain full words. The autocompletion
 // should work with extra spaces.
-TEST_P(TextFragmentSelectorGeneratorTest, WordLimit_ExtraSpaces) {
+TEST_F(TextFragmentSelectorGeneratorTest, WordLimit_ExtraSpaces) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -854,7 +728,7 @@
 
 // When selection starts at the end of a word, selection shouldn't be
 // autocompleted to contain extra words.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        WordLimit_SelectionStartsAndEndsAtWordLimit) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -874,7 +748,7 @@
 }
 
 // Check the case when selections starts with an non text node.
-TEST_P(TextFragmentSelectorGeneratorTest, StartsWithImage) {
+TEST_F(TextFragmentSelectorGeneratorTest, StartsWithImage) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -893,7 +767,7 @@
 }
 
 // Check the case when selections starts with an non text node.
-TEST_P(TextFragmentSelectorGeneratorTest, StartsWithBlockWithImage) {
+TEST_F(TextFragmentSelectorGeneratorTest, StartsWithBlockWithImage) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -915,7 +789,7 @@
 
 // Check the case when selections starts with a node nested in "inline-block"
 // node. crbug.com/1151474
-TEST_P(TextFragmentSelectorGeneratorTest, StartsWithInlineBlockChild) {
+TEST_F(TextFragmentSelectorGeneratorTest, StartsWithInlineBlockChild) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -951,7 +825,7 @@
 }
 
 // Check the case when selections ends with an non text node.
-TEST_P(TextFragmentSelectorGeneratorTest, EndswithImage) {
+TEST_F(TextFragmentSelectorGeneratorTest, EndswithImage) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -971,7 +845,7 @@
 }
 
 // Check the case when selections starts at the end of the previous block.
-TEST_P(TextFragmentSelectorGeneratorTest, StartIsEndofPrevBlock) {
+TEST_F(TextFragmentSelectorGeneratorTest, StartIsEndofPrevBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -989,7 +863,7 @@
 }
 
 // Check the case when selections starts at the end of the previous block.
-TEST_P(TextFragmentSelectorGeneratorTest, EndIsStartofNextBlock) {
+TEST_F(TextFragmentSelectorGeneratorTest, EndIsStartofNextBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1019,7 +893,7 @@
 // want to ensure it correctly traverses the tree back to the previous text node
 // and not to the <div>(sibling of second <p>).
 // See crbug.com/1154308 for more context.
-TEST_P(TextFragmentSelectorGeneratorTest, PrevNodeIsSiblingsChild) {
+TEST_F(TextFragmentSelectorGeneratorTest, PrevNodeIsSiblingsChild) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
 
@@ -1053,7 +927,7 @@
 // want to ensure it correctly traverses the tree back to the previous text by
 // correctly skipping the invisible div but not skipping the second <p>.
 // See crbug.com/1154308 for more context.
-TEST_P(TextFragmentSelectorGeneratorTest, PrevPrevNodeIsSiblingsChild) {
+TEST_F(TextFragmentSelectorGeneratorTest, PrevPrevNodeIsSiblingsChild) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   // HTML is intentionally not formatted. Adding new lines and indentation
@@ -1074,7 +948,7 @@
 
 // Checks that for short selection that have nested block element range selector
 // is used.
-TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode_Interrupted) {
+TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode_Interrupted) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1091,7 +965,7 @@
 }
 
 // Check min number of words is used for context if possible.
-TEST_P(TextFragmentSelectorGeneratorTest, MultiwordContext) {
+TEST_F(TextFragmentSelectorGeneratorTest, MultiwordContext) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1111,7 +985,7 @@
 }
 
 // Check min number of words is used for range if possible.
-TEST_P(TextFragmentSelectorGeneratorTest, MultiWordRangeSelector) {
+TEST_F(TextFragmentSelectorGeneratorTest, MultiWordRangeSelector) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1132,7 +1006,7 @@
 }
 
 // Checks the case when selection end position is a non text node.
-TEST_P(TextFragmentSelectorGeneratorTest, SelectionEndsWithNonText) {
+TEST_F(TextFragmentSelectorGeneratorTest, SelectionEndsWithNonText) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1154,7 +1028,7 @@
 
 // Checks the case when selection end position is a non text node which doesn't
 // have text child node.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        SelectionEndsWithNonTextWithNoTextChild) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1177,7 +1051,7 @@
 
 // Checks the case when selection end position is a non text node which doesn't
 // have text child node.
-TEST_P(TextFragmentSelectorGeneratorTest, SelectionEndsWithImageDiv) {
+TEST_F(TextFragmentSelectorGeneratorTest, SelectionEndsWithImageDiv) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1199,7 +1073,7 @@
 
 // Checks the case when selected range contains a range with same start and end.
 // The problematic case should have both range end and suffix.
-TEST_P(TextFragmentSelectorGeneratorTest, OverlappingRange) {
+TEST_F(TextFragmentSelectorGeneratorTest, OverlappingRange) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1217,7 +1091,7 @@
 }
 
 // Checks selection across table cells.
-TEST_P(TextFragmentSelectorGeneratorTest, Table) {
+TEST_F(TextFragmentSelectorGeneratorTest, Table) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1246,7 +1120,7 @@
 }
 
 // Checks selection across an input element.
-TEST_P(TextFragmentSelectorGeneratorTest, Input) {
+TEST_F(TextFragmentSelectorGeneratorTest, Input) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1266,7 +1140,7 @@
 
 // Checks selection across a shadow tree. Input that has text value will create
 // a shadow tree,
-TEST_P(TextFragmentSelectorGeneratorTest, InputSubmit) {
+TEST_F(TextFragmentSelectorGeneratorTest, InputSubmit) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1286,7 +1160,7 @@
 
 // Checks selection right after a shadow tree will use the shadow tree for
 // prefix. Input with text value will create a shadow tree.
-TEST_P(TextFragmentSelectorGeneratorTest, InputSubmitPrefix) {
+TEST_F(TextFragmentSelectorGeneratorTest, InputSubmitPrefix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1306,7 +1180,7 @@
 
 // Checks selection right after a shadow tree will use the shadow tree for
 // prefix. Input with text value will create a shadow tree.
-TEST_P(TextFragmentSelectorGeneratorTest, InputSubmitOneWordPrefix) {
+TEST_F(TextFragmentSelectorGeneratorTest, InputSubmitOneWordPrefix) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1324,36 +1198,8 @@
   VerifySelector(start, end, "button-,paragraph,-text");
 }
 
-// TODO(crbug.com/1192047): Update the test to better reflect the real repro
-// steps. Test case for crash in crbug.com/1190137. When selector is requested
-// after callback is set and unused.
-TEST_P(TextFragmentSelectorGeneratorTest, SecondGenerationCrash) {
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-  <p id='p'>First paragraph text</p>
-  )HTML");
-  GetDocument().UpdateStyleAndLayoutTree();
-  Node* p = GetDocument().getElementById("p");
-  const auto& start = Position(p->lastChild(), 0);
-  const auto& end = Position(p->lastChild(), 15);
-  ASSERT_EQ("First paragraph", PlainText(EphemeralRange(start, end)));
-
-  auto callback = WTF::Bind([](const String& generated_selector) {});
-  GetDocument()
-      .GetFrame()
-      ->GetTextFragmentSelectorGenerator()
-      ->SetCallbackForTesting(std::move(callback));
-
-  // This shouldn't crash.
-  GetDocument().GetFrame()->GetTextFragmentSelectorGenerator()->UpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(start, end)));
-  base::RunLoop().RunUntilIdle();
-}
-
 // Basic test case for |GetNextTextBlock|.
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1365,14 +1211,13 @@
   const auto& end = Position(first_paragraph, 20);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("First paragraph", GetDocument()
-                                   .GetFrame()
-                                   ->GetTextFragmentSelectorGenerator()
-                                   ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("First paragraph",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix contains collapsible space.
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ExtraSpace) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ExtraSpace) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1386,15 +1231,14 @@
   const auto& end = Position(first_paragraph, 30);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("First paragraph", GetDocument()
-                                   .GetFrame()
-                                   ->GetTextFragmentSelectorGenerator()
-                                   ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("First paragraph",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix complete text content of the previous
 // block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1408,15 +1252,13 @@
   ASSERT_EQ("Second", PlainText(EphemeralRange(start, end)));
 
   EXPECT_EQ("First paragraph text",
-            GetDocument()
-                .GetFrame()
-                ->GetTextFragmentSelectorGenerator()
-                ->GetPreviousTextBlockForTesting(start));
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when there is a commented block between selection and the
 // available prefix.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetPreviousTextBlock_PrevNode_WithComment) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1434,15 +1276,13 @@
   ASSERT_EQ("Second", PlainText(EphemeralRange(start, end)));
 
   EXPECT_EQ("First paragraph text",
-            GetDocument()
-                .GetFrame()
-                ->GetTextFragmentSelectorGenerator()
-                ->GetPreviousTextBlockForTesting(start));
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix is a text node outside of selection
 // block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevTextNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevTextNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1455,15 +1295,14 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("text", GetDocument()
-                        .GetFrame()
-                        ->GetTextFragmentSelectorGenerator()
-                        ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("text",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix is a parent node text content outside of
 // selection block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ParentNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ParentNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1476,14 +1315,13 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("nested", GetDocument()
-                          .GetFrame()
-                          ->GetTextFragmentSelectorGenerator()
-                          ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("nested",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix contains non-block tag(e.g. <b>).
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedTextNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedTextNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1496,14 +1334,12 @@
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
   EXPECT_EQ("First bold text paragraph",
-            GetDocument()
-                .GetFrame()
-                ->GetTextFragmentSelectorGenerator()
-                ->GetPreviousTextBlockForTesting(start));
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix is collected until nested block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedBlock) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1515,15 +1351,14 @@
   const auto& end = Position(first_paragraph, 15);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("paragraph", GetDocument()
-                             .GetFrame()
-                             ->GetTextFragmentSelectorGenerator()
-                             ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("paragraph",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix includes non-block element but stops at
 // nested block.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetPreviousTextBlock_NestedBlockInNestedText) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1536,14 +1371,13 @@
   const auto& end = Position(first_paragraph, 15);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("bold paragraph", GetDocument()
-                                  .GetFrame()
-                                  ->GetTextFragmentSelectorGenerator()
-                                  ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("bold paragraph",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when available prefix includes invisible block.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetPreviousTextBlock_NestedInvisibleBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1556,15 +1390,14 @@
   const auto& end = Position(first_paragraph, 10);
   ASSERT_EQ("paragraph", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("First", GetDocument()
-                         .GetFrame()
-                         ->GetTextFragmentSelectorGenerator()
-                         ->GetPreviousTextBlockForTesting(start));
+  EXPECT_EQ("First",
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when previous node is used for available prefix when selection
 // is not at index=0 but there is only space before it.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetPreviousTextBlock_SpacesBeforeSelection) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1581,15 +1414,13 @@
   ASSERT_EQ("Second", PlainText(EphemeralRange(start, end)));
 
   EXPECT_EQ("First paragraph text",
-            GetDocument()
-                .GetFrame()
-                ->GetTextFragmentSelectorGenerator()
-                ->GetPreviousTextBlockForTesting(start));
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Check the case when previous node is used for available prefix when selection
 // is not at index=0 but there is only invisible block.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetPreviousTextBlock_InvisibleBeforeSelection) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1610,16 +1441,14 @@
   ASSERT_EQ("Second", PlainText(EphemeralRange(start, end)));
 
   EXPECT_EQ("First paragraph text",
-            GetDocument()
-                .GetFrame()
-                ->GetTextFragmentSelectorGenerator()
-                ->GetPreviousTextBlockForTesting(start));
+            GetTextFragmentSelectorGenerator()->GetPreviousTextBlockForTesting(
+                start));
 }
 
 // Similar test for suffix.
 
 // Basic test case for |GetNextTextBlock|.
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1631,14 +1460,13 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("paragraph text", GetDocument()
-                                  .GetFrame()
-                                  ->GetTextFragmentSelectorGenerator()
-                                  ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix contains collapsible space.
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ExtraSpace) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ExtraSpace) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1653,15 +1481,14 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("paragraph text", GetDocument()
-                                  .GetFrame()
-                                  ->GetTextFragmentSelectorGenerator()
-                                  ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix is complete text content of the next
 // block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1674,15 +1501,14 @@
   const auto& end = Position(first_paragraph, 20);
   ASSERT_EQ("First paragraph text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("Second paragraph text", GetDocument()
-                                         .GetFrame()
-                                         ->GetTextFragmentSelectorGenerator()
-                                         ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "Second paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when there is a commented block between selection and the
 // available suffix.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetNextTextBlock_NextNode_WithComment) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1699,15 +1525,14 @@
   const auto& end = Position(first_paragraph, 20);
   ASSERT_EQ("First paragraph text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("Second paragraph text", GetDocument()
-                                         .GetFrame()
-                                         ->GetTextFragmentSelectorGenerator()
-                                         ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "Second paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix is a text node outside of selection
 // block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextTextNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextTextNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1720,15 +1545,14 @@
   const auto& end = Position(first_paragraph, 20);
   ASSERT_EQ("First paragraph text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("text", GetDocument()
-                        .GetFrame()
-                        ->GetTextFragmentSelectorGenerator()
-                        ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix is a parent node text content outside of
 // selection block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ParentNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ParentNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1740,14 +1564,13 @@
   const auto& end = Position(first_paragraph, 20);
   ASSERT_EQ("First paragraph text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("nested", GetDocument()
-                          .GetFrame()
-                          ->GetTextFragmentSelectorGenerator()
-                          ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "nested",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix contains non-block tag(e.g. <b>).
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedTextNode) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedTextNode) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1759,14 +1582,13 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("bold text paragraph text", GetDocument()
-                                            .GetFrame()
-                                            ->GetTextFragmentSelectorGenerator()
-                                            ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "bold text paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix is collected until nested block.
-TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedBlock) {
+TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
   request.Complete(R"HTML(
@@ -1778,15 +1600,14 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("paragraph", GetDocument()
-                             .GetFrame()
-                             ->GetTextFragmentSelectorGenerator()
-                             ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "paragraph",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix includes non-block element but stops at
 // nested block.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetNextTextBlock_NestedBlockInNestedText) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1799,14 +1620,13 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("bold", GetDocument()
-                        .GetFrame()
-                        ->GetTextFragmentSelectorGenerator()
-                        ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "bold",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when available suffix includes invisible block.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetNextTextBlock_NestedInvisibleBlock) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1819,15 +1639,14 @@
   const auto& end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("paragraph text", GetDocument()
-                                  .GetFrame()
-                                  ->GetTextFragmentSelectorGenerator()
-                                  ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when next node is used for available suffix when selection is
 // not at last index but there is only space after it.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetNextTextBlock_SpacesAfterSelection) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1845,15 +1664,14 @@
   const auto& end = Position(first_paragraph, 27);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("Second paragraph text", GetDocument()
-                                         .GetFrame()
-                                         ->GetTextFragmentSelectorGenerator()
-                                         ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "Second paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when next node is used for available suffix when selection is
 // not at last index but there is only invisible block after it.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetNextTextBlock_InvisibleAfterSelection) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1874,16 +1692,15 @@
   const auto& end = Position(first_paragraph, 27);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("Second paragraph text", GetDocument()
-                                         .GetFrame()
-                                         ->GetTextFragmentSelectorGenerator()
-                                         ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "Second paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
 // Check the case when previous node is used for available prefix when selection
 // is not at last index but there is only invisible block. Invisible block
 // contains another block which also should be invisible.
-TEST_P(TextFragmentSelectorGeneratorTest,
+TEST_F(TextFragmentSelectorGeneratorTest,
        GetNextTextBlock_InvisibleAfterSelection_WithNestedInvisible) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1914,56 +1731,9 @@
   const auto& end = Position(first_paragraph, 27);
   ASSERT_EQ("text", PlainText(EphemeralRange(start, end)));
 
-  EXPECT_EQ("Second paragraph text", GetDocument()
-                                         .GetFrame()
-                                         ->GetTextFragmentSelectorGenerator()
-                                         ->GetNextTextBlockForTesting(end));
+  EXPECT_EQ(
+      "Second paragraph text",
+      GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end));
 }
 
-TEST_P(TextFragmentSelectorGeneratorTest, CheckMetrics_Success) {
-  base::test::ScopedFeatureList feature_list;
-  // Basic exact selector case.
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <div>Test page</div>
-    <p id='first'>First paragraph text that is longer than 20 chars</p>
-    <p id='second'>Second paragraph text</p>
-  )HTML");
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& selected_start = Position(first_paragraph, 0);
-  const auto& selected_end = Position(first_paragraph, 28);
-  ASSERT_EQ("First paragraph text that is",
-            PlainText(EphemeralRange(selected_start, selected_end)));
-
-  VerifySelector(selected_start, selected_end,
-                 "First%20paragraph%20text%20that%20is");
-  VerifyPreemptiveGenerationMetrics(true);
-}
-
-TEST_P(TextFragmentSelectorGeneratorTest, CheckMetrics_Failure) {
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <div>Test page</div>
-    <p id='first'>First paragraph prefix one two three four five six seven
-     eight nine ten to not unique snippet of text followed by suffix</p>
-    <p id='second'>Second paragraph prefix one two three four five six seven
-     eight nine ten to not unique snippet of text followed by suffix</p>
-  )HTML");
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& selected_start = Position(first_paragraph, 80);
-  const auto& selected_end = Position(first_paragraph, 106);
-  ASSERT_EQ("not unique snippet of text",
-            PlainText(EphemeralRange(selected_start, selected_end)));
-  VerifySelectorFails(selected_start, selected_end,
-                      LinkGenerationError::kContextLimitReached);
-  VerifyPreemptiveGenerationMetrics(false);
-}
-
-INSTANTIATE_TEST_SUITE_P(All,
-                         TextFragmentSelectorGeneratorTest,
-                         ::testing::Bool());
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index a701c72..ac8314a4 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -565,6 +565,9 @@
     return false;
   BackgroundColorPaintImageGenerator* generator =
       document->GetFrame()->GetBackgroundColorPaintImageGenerator();
+  // The generator can be null in testing environment.
+  if (!generator)
+    return false;
   return generator->GetBGColorPaintWorkletParams(node, animated_colors, offsets,
                                                  progress);
 }
diff --git a/third_party/blink/renderer/extensions/DIR_METADATA b/third_party/blink/renderer/extensions/DIR_METADATA
new file mode 100644
index 0000000..90b2e9c
--- /dev/null
+++ b/third_party/blink/renderer/extensions/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>Internals>Modularization"
+}
+
+team_email: "platform-architecture-dev@chromium.org"
diff --git a/third_party/blink/renderer/extensions/OWNERS b/third_party/blink/renderer/extensions/OWNERS
new file mode 100644
index 0000000..95fdefa
--- /dev/null
+++ b/third_party/blink/renderer/extensions/OWNERS
@@ -0,0 +1,2 @@
+chrishtr@chromium.org
+haraken@chromium.org
diff --git a/third_party/blink/renderer/extensions/README.md b/third_party/blink/renderer/extensions/README.md
new file mode 100644
index 0000000..90bff3eb
--- /dev/null
+++ b/third_party/blink/renderer/extensions/README.md
@@ -0,0 +1,11 @@
+# The `extensions/` directory
+
+The `extensions/` directory contains embedder-specific, not-web-exposed APIs (e.g., not-web-exposed APIs for Chromium OS etc).
+The directory is useful to implement embedder-specific, not-web-exposed APIs
+using Blink technologies for web-exposed APIs like WebIDL, V8 bindings and Oilpan.
+
+Remember that you should not implement any web-exposed APIs in `extensions/`. Web-exposed APIs should go through the standardization process and be implemented in `core/` or `modules/`. Also, per [the Chromium contributor guideline](https://chromium.googlesource.com/chromium/src/+/main/docs/contributing.md#code-guidelines), code that is not used by Chromium should not be added to `extensions/`.
+
+In terms of dependencies, `extensions/` can depend on `modules/`, `core/` and `platform/`, but not vice versa.
+
+The `extensions/` directory contains sub-directories for individual embedders (e.g., `extensions/chromeos/`). Each sub-directory is linked into the Blink link unit only when the embedder is built.
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index 2db61ec..8b3319e1 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -1019,12 +1019,13 @@
 // Properties of interactive elements.
 //
 
-String AXLayoutObject::TextAlternative(bool recursive,
-                                       bool in_aria_labelled_by_traversal,
-                                       AXObjectSet& visited,
-                                       ax::mojom::blink::NameFrom& name_from,
-                                       AXRelatedObjectVector* related_objects,
-                                       NameSources* name_sources) const {
+String AXLayoutObject::TextAlternative(
+    bool recursive,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited,
+    ax::mojom::blink::NameFrom& name_from,
+    AXRelatedObjectVector* related_objects,
+    NameSources* name_sources) const {
   if (layout_object_) {
     absl::optional<String> text_alternative = GetCSSAltText(GetNode());
     bool found_text_alternative = false;
@@ -1082,9 +1083,9 @@
     }
   }
 
-  return AXNodeObject::TextAlternative(recursive, in_aria_labelled_by_traversal,
-                                       visited, name_from, related_objects,
-                                       name_sources);
+  return AXNodeObject::TextAlternative(
+      recursive, aria_label_or_description_root, visited, name_from,
+      related_objects, name_sources);
 }
 
 //
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
index 432d15f..de27d4a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -89,7 +89,7 @@
 
   // AX name calc.
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::blink::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc b/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc
index d2924bb..9b40a67 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc
@@ -74,12 +74,13 @@
   return false;
 }
 
-String AXListBoxOption::TextAlternative(bool recursive,
-                                        bool in_aria_labelled_by_traversal,
-                                        AXObjectSet& visited,
-                                        ax::mojom::NameFrom& name_from,
-                                        AXRelatedObjectVector* related_objects,
-                                        NameSources* name_sources) const {
+String AXListBoxOption::TextAlternative(
+    bool recursive,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited,
+    ax::mojom::NameFrom& name_from,
+    AXRelatedObjectVector* related_objects,
+    NameSources* name_sources) const {
   // If nameSources is non-null, relatedObjects is used in filling it in, so it
   // must be non-null as well.
   if (name_sources)
@@ -90,7 +91,7 @@
 
   bool found_text_alternative = false;
   String text_alternative = AriaTextAlternative(
-      recursive, in_aria_labelled_by_traversal, visited, name_from,
+      recursive, aria_label_or_description_root, visited, name_from,
       related_objects, name_sources, &found_text_alternative);
   if (found_text_alternative && !name_sources)
     return text_alternative;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h b/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h
index e4bb885..345992a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h
@@ -50,7 +50,7 @@
   bool OnNativeSetSelectedAction(bool) override;
 
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_media_element.cc b/third_party/blink/renderer/modules/accessibility/ax_media_element.cc
index a339d726..482f14b3 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_media_element.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_media_element.cc
@@ -27,7 +27,7 @@
 
 String AccessibilityMediaElement::TextAlternative(
     bool recursive,
-    bool in_aria_labelled_by_traversal,
+    const AXObject* aria_label_or_description_root,
     AXObjectSet& visited,
     ax::mojom::NameFrom& name_from,
     AXRelatedObjectVector* related_objects,
@@ -41,7 +41,7 @@
     return element->GetLocale().QueryString(IDS_MEDIA_PLAYBACK_ERROR);
   }
   return AXLayoutObject::TextAlternative(
-      recursive, in_aria_labelled_by_traversal, visited, name_from,
+      recursive, aria_label_or_description_root, visited, name_from,
       related_objects, name_sources);
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_media_element.h b/third_party/blink/renderer/modules/accessibility/ax_media_element.h
index 7676bee4..afa2cea7 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_media_element.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_media_element.h
@@ -22,7 +22,7 @@
 
   // AXLayoutObject overrides.
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
index bcd8b24..8759d58f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
@@ -174,12 +174,13 @@
   }
 }
 
-String AXMenuListOption::TextAlternative(bool recursive,
-                                         bool in_aria_labelled_by_traversal,
-                                         AXObjectSet& visited,
-                                         ax::mojom::NameFrom& name_from,
-                                         AXRelatedObjectVector* related_objects,
-                                         NameSources* name_sources) const {
+String AXMenuListOption::TextAlternative(
+    bool recursive,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited,
+    ax::mojom::NameFrom& name_from,
+    AXRelatedObjectVector* related_objects,
+    NameSources* name_sources) const {
   // If nameSources is non-null, relatedObjects is used in filling it in, so it
   // must be non-null as well.
   if (name_sources)
@@ -190,7 +191,7 @@
 
   bool found_text_alternative = false;
   String text_alternative = AriaTextAlternative(
-      recursive, in_aria_labelled_by_traversal, visited, name_from,
+      recursive, aria_label_or_description_root, visited, name_from,
       related_objects, name_sources, &found_text_alternative);
   if (found_text_alternative && !name_sources)
     return text_alternative;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
index 74d30ee4..a0588c1 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
@@ -61,7 +61,7 @@
                          SkMatrix44& out_container_transform,
                          bool* clips_children = nullptr) const override;
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 4f440b6..c8803095 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -2868,12 +2868,13 @@
   return name;
 }
 
-String AXNodeObject::TextAlternative(bool recursive,
-                                     bool in_aria_labelled_by_traversal,
-                                     AXObjectSet& visited,
-                                     ax::mojom::blink::NameFrom& name_from,
-                                     AXRelatedObjectVector* related_objects,
-                                     NameSources* name_sources) const {
+String AXNodeObject::TextAlternative(
+    bool recursive,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited,
+    ax::mojom::blink::NameFrom& name_from,
+    AXRelatedObjectVector* related_objects,
+    NameSources* name_sources) const {
   // If nameSources is non-null, relatedObjects is used in filling it in, so it
   // must be non-null as well.
   if (name_sources)
@@ -2914,7 +2915,7 @@
 
   // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 -- aria-label.
   String text_alternative = AriaTextAlternative(
-      recursive, in_aria_labelled_by_traversal, visited, name_from,
+      recursive, aria_label_or_description_root, visited, name_from,
       related_objects, name_sources, &found_text_alternative);
   if (found_text_alternative && !name_sources)
     return text_alternative;
@@ -2930,7 +2931,7 @@
     return text_alternative;
 
   // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 -- from content.
-  if (in_aria_labelled_by_traversal || SupportsNameFromContents(recursive)) {
+  if (aria_label_or_description_root || SupportsNameFromContents(recursive)) {
     Node* node = GetNode();
     if (!IsA<HTMLSelectElement>(node)) {  // Avoid option descendant text
       name_from = ax::mojom::blink::NameFrom::kContents;
@@ -2957,7 +2958,7 @@
     }
   }
 
-  // Step 2H from: http://www.w3.org/TR/accname-aam-1.1
+  // Step 2I from: http://www.w3.org/TR/accname-aam-1.1
   name_from = ax::mojom::blink::NameFrom::kTitle;
   if (name_sources) {
     name_sources->push_back(NameSource(found_text_alternative, kTitleAttr));
@@ -3097,7 +3098,7 @@
       result = child->TextFromDescendants(visited, true);
     } else {
       result =
-          RecursiveTextAlternative(*child, false, visited, child_name_from);
+          RecursiveTextAlternative(*child, nullptr, visited, child_name_from);
     }
 
     if (!result.IsEmpty() && previous && accumulated_text.length() &&
@@ -4723,7 +4724,7 @@
       AXObject* figcaption_ax_object = AXObjectCache().GetOrCreate(figcaption);
       if (figcaption_ax_object) {
         text_alternative =
-            RecursiveTextAlternative(*figcaption_ax_object, false, visited);
+            RecursiveTextAlternative(*figcaption_ax_object, nullptr, visited);
 
         if (related_objects) {
           local_related_objects.push_back(
@@ -4786,7 +4787,7 @@
       AXObject* caption_ax_object = AXObjectCache().GetOrCreate(caption);
       if (caption_ax_object) {
         text_alternative =
-            RecursiveTextAlternative(*caption_ax_object, false, visited);
+            RecursiveTextAlternative(*caption_ax_object, nullptr, visited);
         if (related_objects) {
           local_related_objects.push_back(
               MakeGarbageCollected<NameSourceRelatedObject>(caption_ax_object,
@@ -4845,7 +4846,7 @@
       AXObject* title_ax_object = AXObjectCache().GetOrCreate(title);
       if (title_ax_object && !visited.Contains(title_ax_object)) {
         text_alternative =
-            RecursiveTextAlternative(*title_ax_object, false, visited);
+            RecursiveTextAlternative(*title_ax_object, nullptr, visited);
         if (related_objects) {
           local_related_objects.push_back(
               MakeGarbageCollected<NameSourceRelatedObject>(title_ax_object,
@@ -4880,7 +4881,7 @@
       // Avoid an infinite loop
       if (legend_ax_object && !visited.Contains(legend_ax_object)) {
         text_alternative =
-            RecursiveTextAlternative(*legend_ax_object, false, visited);
+            RecursiveTextAlternative(*legend_ax_object, nullptr, visited);
 
         if (related_objects) {
           local_related_objects.push_back(
@@ -5125,7 +5126,7 @@
     if (ruby_annotation_ax_object) {
       AXObjectSet visited;
       description =
-          RecursiveTextAlternative(*ruby_annotation_ax_object, true, visited);
+          RecursiveTextAlternative(*ruby_annotation_ax_object, this, visited);
       if (related_objects) {
         related_objects->push_back(
             MakeGarbageCollected<NameSourceRelatedObject>(
@@ -5158,7 +5159,7 @@
       if (caption_ax_object) {
         AXObjectSet visited;
         description =
-            RecursiveTextAlternative(*caption_ax_object, false, visited);
+            RecursiveTextAlternative(*caption_ax_object, nullptr, visited);
         if (related_objects) {
           related_objects->push_back(
               MakeGarbageCollected<NameSourceRelatedObject>(caption_ax_object,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
index 5ad142c..b52d213 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -193,7 +193,7 @@
   String GetName(ax::mojom::blink::NameFrom&,
                  AXObjectVector* name_objects) const override;
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::blink::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index eca07772..ce35c04 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -2876,7 +2876,7 @@
   // Initialize |name_from|, as TextAlternative() might never set it in some
   // cases.
   name_from = ax::mojom::blink::NameFrom::kNone;
-  String text = TextAlternative(false, false, visited, name_from,
+  String text = TextAlternative(false, nullptr, visited, name_from,
                                 &related_objects, nullptr);
 
   ax::mojom::blink::Role role = RoleValue();
@@ -2898,29 +2898,30 @@
   AXObjectSet visited;
   ax::mojom::blink::NameFrom tmp_name_from;
   AXRelatedObjectVector tmp_related_objects;
-  String text = TextAlternative(false, false, visited, tmp_name_from,
+  String text = TextAlternative(false, nullptr, visited, tmp_name_from,
                                 &tmp_related_objects, name_sources);
   text = text.SimplifyWhiteSpace(IsHTMLSpace<UChar>);
   return text;
 }
 
-String AXObject::RecursiveTextAlternative(const AXObject& ax_obj,
-                                          bool in_aria_labelled_by_traversal,
-                                          AXObjectSet& visited) {
+String AXObject::RecursiveTextAlternative(
+    const AXObject& ax_obj,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited) {
   ax::mojom::blink::NameFrom tmp_name_from;
-  return RecursiveTextAlternative(ax_obj, in_aria_labelled_by_traversal,
+  return RecursiveTextAlternative(ax_obj, aria_label_or_description_root,
                                   visited, tmp_name_from);
 }
 
 String AXObject::RecursiveTextAlternative(
     const AXObject& ax_obj,
-    bool in_aria_labelled_by_traversal,
+    const AXObject* aria_label_or_description_root,
     AXObjectSet& visited,
     ax::mojom::blink::NameFrom& name_from) {
-  if (visited.Contains(&ax_obj) && !in_aria_labelled_by_traversal)
+  if (visited.Contains(&ax_obj) && !aria_label_or_description_root)
     return String();
 
-  return ax_obj.TextAlternative(true, in_aria_labelled_by_traversal, visited,
+  return ax_obj.TextAlternative(true, aria_label_or_description_root, visited,
                                 name_from, nullptr, nullptr);
 }
 
@@ -3002,20 +3003,21 @@
          (!ParentObject() || !ParentObject()->IsHiddenViaStyle());
 }
 
-String AXObject::AriaTextAlternative(bool recursive,
-                                     bool in_aria_labelled_by_traversal,
-                                     AXObjectSet& visited,
-                                     ax::mojom::blink::NameFrom& name_from,
-                                     AXRelatedObjectVector* related_objects,
-                                     NameSources* name_sources,
-                                     bool* found_text_alternative) const {
+String AXObject::AriaTextAlternative(
+    bool recursive,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited,
+    ax::mojom::blink::NameFrom& name_from,
+    AXRelatedObjectVector* related_objects,
+    NameSources* name_sources,
+    bool* found_text_alternative) const {
   String text_alternative;
   bool already_visited = visited.Contains(this);
   visited.insert(this);
 
   // Step 2A from: http://www.w3.org/TR/accname-aam-1.1
   // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
-  if (!in_aria_labelled_by_traversal &&
+  if (!aria_label_or_description_root &&
       IsHiddenForTextAlternativeCalculation()) {
     *found_text_alternative = true;
     return String();
@@ -3023,7 +3025,7 @@
 
   // Step 2B from: http://www.w3.org/TR/accname-aam-1.1
   // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
-  if (!in_aria_labelled_by_traversal && !already_visited) {
+  if (!aria_label_or_description_root && !already_visited) {
     name_from = ax::mojom::blink::NameFrom::kRelatedElement;
 
     // Check ARIA attributes.
@@ -3116,9 +3118,11 @@
     AXObject* ax_element = AXObjectCache().GetOrCreate(element);
     if (ax_element) {
       found_valid_element = true;
-
-      String result = RecursiveTextAlternative(
-          *ax_element, in_aria_labelledby_traversal, visited);
+      AXObject* aria_labelled_by_node = nullptr;
+      if (in_aria_labelledby_traversal)
+        aria_labelled_by_node = ax_element;
+      String result =
+          RecursiveTextAlternative(*ax_element, aria_labelled_by_node, visited);
       visited.insert(ax_element);
       local_related_objects.push_back(
           MakeGarbageCollected<NameSourceRelatedObject>(ax_element, result));
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h
index 564c9af7..6d2fb4a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -619,7 +619,7 @@
   // Internal functions used by name and description, above.
   typedef HeapHashSet<Member<const AXObject>> AXObjectSet;
   virtual String TextAlternative(bool recursive,
-                                 bool in_aria_labelled_by_traversal,
+                                 const AXObject* aria_label_or_description_root,
                                  AXObjectSet& visited,
                                  ax::mojom::blink::NameFrom& name_from,
                                  AXRelatedObjectVector* related_objects,
@@ -1386,21 +1386,23 @@
 
   // Used only inside textAlternative():
   static String CollapseWhitespace(const String&);
-  static String RecursiveTextAlternative(const AXObject&,
-                                         bool in_aria_labelled_by_traversal,
-                                         AXObjectSet& visited);
-  static String RecursiveTextAlternative(const AXObject&,
-                                         bool in_aria_labelled_by_traversal,
-                                         AXObjectSet& visited,
-                                         ax::mojom::blink::NameFrom& name_from);
+  static String RecursiveTextAlternative(
+      const AXObject&,
+      const AXObject* aria_label_or_description_root,
+      AXObjectSet& visited);
+  static String RecursiveTextAlternative(
+      const AXObject&,
+      const AXObject* aria_label_or_description_root,
+      AXObjectSet& visited,
+      ax::mojom::blink::NameFrom& name_from);
   String AriaTextAlternative(bool recursive,
-                             bool in_aria_labelled_by_traversal,
+                             const AXObject* aria_label_or_description_root,
                              AXObjectSet& visited,
                              ax::mojom::blink::NameFrom&,
                              AXRelatedObjectVector*,
                              NameSources*,
                              bool* found_text_alternative) const;
-  String TextFromElements(bool in_aria_labelled_by_traversal,
+  String TextFromElements(bool in_aria_labelledby_traversal,
                           AXObjectSet& visited,
                           HeapVector<Member<Element>>& elements,
                           AXRelatedObjectVector* related_objects) const;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc b/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
index e57ff99..54f06485e6 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
@@ -99,7 +99,7 @@
 
 String AXValidationMessage::TextAlternative(
     bool recursive,
-    bool in_aria_labelled_by_traversal,
+    const AXObject* aria_label_or_description_root,
     AXObjectSet& visited,
     ax::mojom::NameFrom& name_from,
     AXRelatedObjectVector* related_objects,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_validation_message.h b/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
index 1ac7447..c6482fa4 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
@@ -38,7 +38,7 @@
   bool IsValidationMessage() const override { return true; }
   bool IsVisible() const override;
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
index c00a326..a91bb0d0 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
@@ -85,17 +85,18 @@
   return accessible_node_;
 }
 
-String AXVirtualObject::TextAlternative(bool recursive,
-                                        bool in_aria_labelled_by_traversal,
-                                        AXObjectSet& visited,
-                                        ax::mojom::NameFrom& name_from,
-                                        AXRelatedObjectVector* related_objects,
-                                        NameSources* name_sources) const {
+String AXVirtualObject::TextAlternative(
+    bool recursive,
+    const AXObject* aria_label_or_description_root,
+    AXObjectSet& visited,
+    ax::mojom::NameFrom& name_from,
+    AXRelatedObjectVector* related_objects,
+    NameSources* name_sources) const {
   if (!accessible_node_)
     return String();
 
   bool found_text_alternative = false;
-  return AriaTextAlternative(recursive, in_aria_labelled_by_traversal, visited,
+  return AriaTextAlternative(recursive, aria_label_or_description_root, visited,
                              name_from, related_objects, name_sources,
                              &found_text_alternative);
 }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
index a5c01f64..c796e00f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
@@ -30,7 +30,7 @@
                                      bool& result) const override;
   AccessibleNode* GetAccessibleNode() const override;
   String TextAlternative(bool recursive,
-                         bool in_aria_labelled_by_traversal,
+                         const AXObject* aria_label_or_description_root,
                          AXObjectSet& visited,
                          ax::mojom::NameFrom&,
                          AXRelatedObjectVector*,
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
index f42b70cf..33aece5 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -21,6 +21,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
+#include "base/trace_event/base_tracing.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "media/base/media_log.h"
@@ -207,6 +208,7 @@
 
 bool RTCVideoDecoderAdapter::InitializeSync(
     const media::VideoDecoderConfig& config) {
+  TRACE_EVENT0("webrtc", "RTCVideoDecoderAdapter::InitializeSync");
   DVLOG(3) << __func__;
   // Can be called on |worker_thread_| or |decoding_thread_|.
   DCHECK(!media_task_runner_->RunsTasksInCurrentSequence());
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
index 4e45a4b0..e4f0b29 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
+#include "base/trace_event/base_tracing.h"
 #include "build/build_config.h"
 #include "media/base/decoder_factory.h"
 #include "media/base/media_util.h"
@@ -342,6 +343,7 @@
 std::unique_ptr<webrtc::VideoDecoder>
 RTCVideoDecoderFactory::CreateVideoDecoder(
     const webrtc::SdpVideoFormat& format) {
+  TRACE_EVENT0("webrtc", "RTCVideoDecoderFactory::CreateVideoDecoder");
   DVLOG(2) << __func__;
   CheckAndWaitDecoderSupportStatusIfNeeded();
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 20b63a70..89fef926 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -373,6 +373,7 @@
     },
     {
       name: "CompositeBGColorAnimation",
+      status: "experimental",
     },
     {
       name: "CompositeClipPathAnimation",
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index a62db40..e2257cc 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -188,3 +188,4 @@
 
 # Sheriff 2021-06-02
 crbug.com/1215390 [ Linux ] external/wpt/pointerevents/pointerevent_pointerId_scope.html [ Pass Failure ]
+crbug.com/1215530 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index aa987bd..b3a9767 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5232,8 +5232,9 @@
 crbug.com/993671 [ Win ] http/tests/media/video-frame-size-change.html [ Pass Failure ]
 
 #Sherrif 2019-08-16
-crbug.com/994692 [ Linux ] compositing/reflections/nested-reflection-anchor-point.html [ Pass Failure ]
-crbug.com/994692 [ Win ] compositing/reflections/nested-reflection-anchor-point.html [ Pass Failure ]
+#TODO(michaelludwig): Uncomment after more general suppression is rebased.
+#crbug.com/994692 [ Linux ] compositing/reflections/nested-reflection-anchor-point.html [ Pass Failure ]
+#crbug.com/994692 [ Win ] compositing/reflections/nested-reflection-anchor-point.html [ Pass Failure ]
 
 crbug.com/996219 [ Win ] virtual/text-antialias/emoji-vertical-origin-visual.html [ Failure ]
 
@@ -5366,6 +5367,36 @@
 crbug.com/1030258 http/tests/devtools/network/network-cookies-pane.js [ Pass Failure ]
 crbug.com/1041830 http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile.js [ Pass Failure ]
 
+# TODO(michaelludwig): Rebaseline these after Skia roll lands making changes to
+# image filters. See crbug.com/1143929
+crbug.com/1143929 compositing/reflections/animation-inside-reflection.html [ Pass Failure ]
+crbug.com/1143929 compositing/reflections/nested-reflection-anchor-point.html [ Pass Failure ]
+crbug.com/1143929 compositing/reflections/nested-reflection-animated.html [ Pass Failure ]
+crbug.com/1143929 compositing/reflections/nested-reflection-transformed.html [ Pass Failure ]
+crbug.com/1143929 compositing/reflections/nested-reflection-transformed2.html [ Pass Failure ]
+crbug.com/1143929 compositing/reflections/reflection-in-composited.html [ Pass Failure ]
+crbug.com/1143929 css3/filters/effect-combined-hw.html [ Pass Failure ]
+crbug.com/1143929 css3/filters/effect-combined.html [ Pass Failure ]
+crbug.com/1143929 css3/filters/regions-expanding.html [ Pass Failure ]
+crbug.com/1143929 external/wpt/css/css-transforms/preserve3d-and-filter-with-perspective.html [ Pass Failure ]
+crbug.com/1143929 external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix.html [ Pass Failure ]
+crbug.com/1143929 fast/css/transformed-mask.html [ Pass Failure ]
+crbug.com/1143929 fast/reflections/opacity-reflection-transform.html [ Pass Failure ]
+crbug.com/1143929 images/color-profile-image-filter-all.html [ Pass Failure ]
+crbug.com/1143929 paint/invalidation/reflection/reflection-with-rotation.html [ Pass Failure ]
+crbug.com/1143929 svg/W3C-SVG-1.1/filters-blend-01-b.svg [ Pass Failure ]
+crbug.com/1143929 svg/W3C-SVG-1.1/filters-example-01-b.svg [ Pass Failure ]
+crbug.com/1143929 svg/W3C-SVG-1.1/filters-turb-02-f.svg [ Pass Failure ]
+crbug.com/1143929 svg/batik/filters/feTile.svg [ Pass Failure ]
+crbug.com/1143929 svg/batik/text/smallFonts.svg [ Pass Failure ]
+crbug.com/1143929 svg/batik/text/textFeatures.svg [ Pass Failure ]
+crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-dom-in-attr.html [ Pass Failure ]
+crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr.html [ Pass Failure ]
+crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr.html [ Pass Failure ]
+crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop.html [ Pass Failure ]
+crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop.html [ Pass Failure ]
+crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop.html [ Pass Failure ]
+
 # Sheriff 2019-12-13
 crbug.com/1032451 [ Win7 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window.html [ Failure Pass ]
 crbug.com/1033852 [ Win7 ] virtual/plz-dedicated-worker/external/wpt/fetch/api/idlharness.any.sharedworker.html [ Failure ]
@@ -6596,11 +6627,6 @@
 crbug.com/1208774 [ Mac ] external/wpt/webcodecs/videoDecoder-codec-specific.any.html?h264_annexb [ Pass Failure ]
 crbug.com/1208774 [ Mac ] external/wpt/webcodecs/videoDecoder-codec-specific.any.worker.html?h264_annexb [ Pass Failure ]
 
-# To unblock devtools-frontend TypeScript upgrade
-crbug.com/1209833 http/tests/devtools/runtime/runtime-getProperties.js [ Skip ]
-crbug.com/1209833 http/tests/devtools/runtime/runtime-localStorage-getProperties.js [ Skip ]
-crbug.com/1209833 http/tests/devtools/runtime/evaluate-timeout.js [ Skip ]
-
 # For SkiaRenderer on MacOS
 crbug.com/1208173 [ Mac ] animations/animation-paused-hardware.html [ Failure ]
 crbug.com/1208173 [ Mac ] animations/missing-values-first-keyframe.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html
index 2797a1e..bf744da 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/colspan-redistribution.html
@@ -41,7 +41,7 @@
   <li class="error">Red paragraphs are major browser disagreements</li>
 </ol>
 
-<h2>Colspan&gt;1 cell's percentage distribution</h2>
+<h2>Colspan&gt;1 cell's percentage distribution auto tables</h2>
 <p>Rules</p>
 <ul>
   <li>Percentages can only be redistributed to non-percentage cells.</li>
@@ -100,6 +100,87 @@
   </tr>
 </table>
 
+<h2>Colspan&gt;1 cell's percentage distribution fixed tables</h2>
+<p>Colspan cells distribute width over col widths.
+<p>Rules</p>
+<ul>
+  <li>Percentages are not distributed to fixed columns.</li>
+  <li>Percentages are not distributed to percentage columns.</li>
+  <li>Percentages are distributed to auto columns, each column gets distributed%/colspan percent.</li>
+</ul>
+<p class="testdesc">Auto column distribution
+auto colums get percentage widths distributed evenly.
+C0/C1 become 25% columns.
+Assignable table size is 400-4*8=368. Column size is 25% of 368 = 92px</p>
+<p class="error">FF disagrees in how border-spacing is handled and ends up with slightly different cell widths. </p>
+<table style="table-layout:fixed; width: 400px">
+  <col style="width:auto">
+  <col style="width:auto">
+  <tr>
+    <td colspan="2" style="width:50%">50%</td>
+    <td>a</td>
+  </tr>
+  <tr>
+    <td data-expected-width=92>a</td>
+    <td data-expected-width=92>aa</td>
+    <td>a</td>
+  </tr>
+</table>
+
+<p class="testdesc">Fixed column distribution
+fixed columns do not get percentage distribution.</p>
+<table style="table-layout:fixed; width: 400px">
+  <col style="width:50px">
+  <col style="width:50px">
+  <tr>
+    <td colspan="2" style="width:50%">50%</td>
+    <td>a</td>
+  </tr>
+  <tr>
+    <td data-expected-width="50">a</td>
+    <td data-expected-width="50">a</td>
+    <td>a</td>
+  </tr>
+</table>
+
+<p class="testdesc">Percentage column distribution
+percentage columns do not get percentage distribution.</p>
+<table style="table-layout:fixed; width: 400px">
+  <col style="width:12.5%">
+  <col style="width:25%">
+  <tr>
+    <td colspan="2" style="width:50%">50%</td>
+    <td>a</td>
+  </tr>
+  <tr>
+    <td data-expected-width="46">a</td>
+    <td data-expected-width="92">a</td>
+    <td>a</td>
+  </tr>
+</table>
+
+<p class="testdesc">Distribute over percentage/auto/fixed mix cells
+Collspanned TD distributes 50%. Auto TD gets 50%/(colspanned span = 4): 12.5%
+12.5%* 400px is 50.
+</p>
+<table style="table-layout:fixed; width: 400px;border-spacing:0">
+  <col style="width:25%">
+  <col style="width:25px">
+  <col style="width:25px">
+  <col style="width:auto">
+  <tr>
+    <td colspan="4" style="width:50%">50%</td>
+    <td>a</td>
+  </tr>
+  <tr>
+    <td></td>
+    <td>a</td>
+    <td>a</td>
+    <td data-expected-width="50" style="background-color:yellow">a</td>
+    <td>a</td>
+  </tr>
+</table>
+
 <h2>Colspan&gt;1 cell's minimum width distribution</h2>
 <h3>All unconstrained columns</h3>
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/colspan-redistribution-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/colspan-redistribution-expected.txt
deleted file mode 100644
index 0e697f7..0000000
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/colspan-redistribution-expected.txt
+++ /dev/null
@@ -1,120 +0,0 @@
-This is a testharness.js-based test.
-PASS table 1
-PASS table 2
-FAIL table 3 assert_equals: 
-<table data-expected-width="492">
-  <tbody><tr>
-    <td data-expected-width="46"></td>
-    <td></td>
-    <td>x</td>
-  </tr>
-  <tr>
-    <td colspan="2" style="width:20%"><div style="width:100px">100px</div></td>
-</tr></tbody></table>
-width expected 46 but got 92
-PASS table 4
-PASS table 5
-PASS table 6
-PASS table 7
-PASS table 8
-FAIL table 9 assert_equals: 
-<table data-expected-width="344">
-  <tbody><tr>
-    <td style="width:20px" data-expected-width="146"><div style="width:100px">20/100px</div></td>
-    <td style="width:40px"><div style="width:100px">40/100px</div></td>
-    <td style="width:20px">x</td>
-  </tr>
-  <tr>
-    <td data-expected-width="300" colspan="2" style=""><div style="width:300px">300px min</div></td>
-  </tr>
-</tbody></table>
-width expected 146 but got 100
-PASS table 10
-PASS table 11
-PASS table 12
-PASS table 13
-PASS table 14
-FAIL table 15 assert_equals: 
-<table style="width:1px" data-expected-width="166">
-  <tbody><tr>
-    <td style="width:70px" data-expected-width="42">0</td>
-    <td style="width:70px" data-expected-width="42">0</td>
-    <td data-expected-width="50"><div style="width:50px">50</div></td>
-  </tr>
-  <tr>
-    <td colspan="3"><div style="width:150px"></div>
-    </td>
-  </tr>
-</tbody></table>
-width expected 42 but got 49
-PASS table 16
-PASS table 17
-PASS table 18
-FAIL table 19 assert_equals: 
-<table style="width:1px" data-expected-width="252">
-  <tbody><tr>
-    <td style="width:40%" data-expected-width="80"><div style="width:20px">40%</div></td>
-    <td style="width:50px" data-expected-width="120"><div style="width:50px">50</div></td>
-    <td data-expected-width="20" style="width:100px"><div style="width:20px">20</div></td>
-  </tr>
-  <tr>
-    <td colspan="2" data-expected-width="208"><div style="width:208px">208px min</div></td>
-  </tr>
-</tbody></table>
-width expected 80 but got 57
-PASS table 20
-PASS table 21
-FAIL table 22 assert_equals: 
-<table data-expected-width="532">
-  <tbody><tr>
-    <td colspan="2"><div style="width:208px">200</div></td>
-    <td><div style="width:50px">50</div></td>
-  </tr>
-  <tr>
-    <td><div style="width:50px">50</div></td>
-    <td colspan="2"><div style="width:408px">400</div></td>
-  </tr>
-  <tr>
-    <td data-expected-width="100">Auto</td>
-    <td data-expected-width="267"><div style="width:50px">Auto</div></td>
-    <td data-expected-width="133">Auto</td>
-  </tr>
-</tbody></table>
-width expected 532 but got 482
-FAIL table 23 assert_equals: 
-<table data-expected-width="482">
-  <tbody><tr>
-    <td colspan="2"><div style="width:408px">400</div></td>
-    <td><div style="width:50px">50</div></td>
-  </tr>
-  <tr>
-    <td><div style="width:50px">50</div></td>
-    <td colspan="2"><div style="width:208px">200</div></td>
-  </tr>
-  <tr>
-    <td data-expected-width="200">Auto</td>
-    <td data-expected-width="200"><div style="width:50px">Auto</div></td>
-    <td data-expected-width="50">Auto</td>
-  </tr>
-</tbody></table>
-width expected 482 but got 532
-FAIL table 24 assert_equals: 
-<table data-expected-width="740">
-  <tbody><tr>
-    <td colspan="3"><div style="width:316px">300</div></td>
-    <td><div style="width:50px">50</div></td>
-  </tr>
-  <tr>
-    <td><div style="width:50px">50</div></td>
-    <td colspan="3"><div style="width:616px">600</div></td>
-  </tr>
-  <tr>
-    <td data-expected-width="100">Auto</td>
-    <td data-expected-width="240"><div style="width:50px">Auto</div></td>
-    <td data-expected-width="240"><div style="width:50px">Auto</div></td>
-    <td data-expected-width="120">Auto</td>
-  </tr>
-</tbody></table>
-width expected 740 but got 690
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/runtime/evaluate-timeout-expected.txt b/third_party/blink/web_tests/http/tests/devtools/runtime/evaluate-timeout-expected.txt
index 7f0380f..2d345b7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/runtime/evaluate-timeout-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/runtime/evaluate-timeout-expected.txt
@@ -15,10 +15,13 @@
         _customPreview : null
         _description : "2"
         _hasChildren : false
+        _objectId : undefined
+        _preview : undefined
         _runtimeAgent : <object>
         _runtimeModel : <object>
         _subtype : undefined
         _type : "number"
+        _unserializableValue : undefined
         _value : 2
     }
 }
@@ -43,10 +46,13 @@
         _customPreview : null
         _description : "2"
         _hasChildren : false
+        _objectId : undefined
+        _preview : undefined
         _runtimeAgent : <object>
         _runtimeModel : <object>
         _subtype : undefined
         _type : "number"
+        _unserializableValue : undefined
         _value : 2
     }
 }
diff --git a/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-getProperties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-getProperties-expected.txt
index 58ac828..b70b20b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-getProperties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-getProperties-expected.txt
@@ -19,7 +19,10 @@
         objectId : <string>
         type : "function"
     }
+    symbol : undefined
     synthetic : false
+    syntheticSetter : undefined
+    value : undefined
     wasThrown : false
     writable : false
 }
@@ -35,7 +38,11 @@
     isOwn : true
     name : "foo"
     private : false
+    setter : undefined
+    symbol : undefined
     synthetic : false
+    syntheticSetter : undefined
+    value : undefined
     wasThrown : false
     writable : false
 }
diff --git a/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-localStorage-getProperties-expected.txt b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-localStorage-getProperties-expected.txt
index 7f97890..d96639e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-localStorage-getProperties-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-localStorage-getProperties-expected.txt
@@ -2,10 +2,14 @@
 
 {
     enumerable : true
+    getter : undefined
     isOwn : true
     name : "testProperty"
     private : false
+    setter : undefined
+    symbol : undefined
     synthetic : false
+    syntheticSetter : undefined
     value : {
         description : "testPropertyValue"
         type : "string"
diff --git a/third_party/blink/web_tests/platform/linux/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/linux/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..fb7e80c8
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..ee4fd22b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..f30b745
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..d1a028a9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..251937fe
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/mac/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..a44187b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..c9c49801
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/win/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..d81cf1c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..25d294b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/win7/svg/text/bidi-textlength-expected.png
new file mode 100644
index 0000000..c0c22be
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/text/bidi-textlength.html b/third_party/blink/web_tests/svg/text/bidi-textlength.html
new file mode 100644
index 0000000..1e79ebc
--- /dev/null
+++ b/third_party/blink/web_tests/svg/text/bidi-textlength.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+     width="600" height="600" viewBox="0 0 300 300">
+<defs>
+<path id="Path2" style="fill:none; stroke:lime;" transform="scale(0.30,0.50)"
+      d="M 100 100 C100 0 400 00 400 100 C 400 200 100 200 100 100 z"/>
+</defs>
+<g transform="translate(30,40)">
+<use xlink:href="#Path2"/>
+<text font-size="15" style="direction:rtl;">
+<textPath xlink:href="#Path2" startOffset="90%" style="letter-spacing: 10px">ריווח אותיות</textPath>
+<textPath xlink:href="#Path2" startOffset="90%" textLength="200"><tspan dy="-20">طول النص</tspan></textPath>
+<textPath xlink:href="#Path2" startOffset="90%" textLength="200" lengthAdjust="spacingAndGlyphs"><tspan dy="-40">فاصله و حروف کوچک</tspan></textPath>
+</text>
+
+<text font-size="15" style="direction:rtl;">
+<tspan x="270" y="160" style="letter-spacing: 10px">ריווח אותיות</tspan>
+<tspan x="270" y="180" textLength="300">طول النص</tspan>
+<tspan x="270" y="200" textLength="300" lengthAdjust="spacingAndGlyphs">فاصله و حروف کوچک</tspan>
+<tspan x="270" y="220" textLength="300">🆓🆔🆕🆖🆗نعم🆘🆙🆚</tspan>
+</text>
+</g>
+</svg>
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 7499702..68bf3e2 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,10 +1,10 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 2.8.1-12
+Version: 2.8.1-30
 CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:2.6.4
-Date: 20210518
-Revision: 1dffb553613d8bcaa5440d27b411ae1ff22bf68b
+Date: 20210602
+Revision: 7ab0f4eda9a8a1d7ccd334fa7f9fef4b038a1c24
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/tools/clang/scripts/analyze_includes.py b/tools/clang/scripts/analyze_includes.py
index f37f4dd..402553d3 100755
--- a/tools/clang/scripts/analyze_includes.py
+++ b/tools/clang/scripts/analyze_includes.py
@@ -355,12 +355,27 @@
 
 
   log('Computing added sizes...')
-  added_sizes = {name: 0 for name in includes}
+
+  # Split each src -> dst edge in includes into src -> (src,dst) -> dst, so that
+  # we can compute how much each include graph edge adds to the size by doing
+  # dominance analysis on the (src,dst) nodes.
+  augmented_includes = {}
+  for src in includes:
+    augmented_includes[src] = set()
+    for dst in includes[src]:
+      augmented_includes[src].add((src, dst))
+      augmented_includes[(src, dst)] = {dst}
+
+  added_sizes = {node: 0 for node in augmented_includes}
   for r in roots:
-    doms = compute_doms(r, includes)
-    for n in doms:
-      for d in doms[n]:
-        added_sizes[d] += sizes[n]
+    doms = compute_doms(r, augmented_includes)
+    for node in doms:
+      if not node in sizes:
+        # Skip the (src,dst) pseudo nodes.
+        continue
+      for dom in doms[node]:
+        added_sizes[dom] += sizes[node]
+
 
   # Assign a number to each filename for tighter JSON representation.
   names = []
@@ -385,11 +400,13 @@
           'date': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'),
           'files': names,
           'roots': [nr(x) for x in sorted(roots)],
-          'includes': [[nr(x) for x in includes[n]] for n in names],
+          'includes': [[nr(x) for x in sorted(includes[n])] for n in names],
           'included_by': [[nr(x) for x in included_by[n]] for n in names],
           'sizes': [sizes[n] for n in names],
           'tsizes': [trans_sizes[n] for n in names],
           'asizes': [added_sizes[n] for n in names],
+          'esizes': [[added_sizes[(s, d)] for d in sorted(includes[s])]
+                     for s in names],
           'prevalence': [prevalence[n] for n in names],
       }, json_file)
 
diff --git a/tools/clang/scripts/include-analysis.html b/tools/clang/scripts/include-analysis.html
index b600dc95..2aa056e 100644
--- a/tools/clang/scripts/include-analysis.html
+++ b/tools/clang/scripts/include-analysis.html
@@ -11,11 +11,12 @@
     tr td { text-align: right; }
     tr td:nth-child(1) { text-align: left; }
     tr td:nth-child(2) { text-align: left; }
+    table#edges tr td:nth-child(3) { text-align: left; }
     tbody tr:hover { background-color: #dddddd; }
     th { position: sticky; top: 0; background-color: #ffffff }
-    th:nth-child(n+2) { cursor: pointer; }
+    table#files th:nth-child(n+2) { cursor: pointer; }
     th.highlighted { background-color: #dddddd }
-    #filterResults { font-weight: bold }
+    #filterResults, #edgeFilterResults { font-weight: bold }
     </style>
   </head>
   <body>
@@ -28,17 +29,24 @@
 
 <p>Number of files: <span id="numFiles">x</span>. Total file size: <span id="totFileSize">x</span> bytes.</p>
 
+<button onClick="changeState({view: 'files'})">Per-File Analysis</button>
+<button onClick="changeState({view: 'edges'})">Per-Edge Analysis</button>
+
 <hr>
 
+<div id="filesview">
+
+<h2>Per-File Analysis</h2>
+
 <p>
-<label for="filter">Filter: (regex, includes:&lt;file&gt;, or includedBy:&lt;file&gt;)</label>
-<input type="text" id="filter" name="filter" size="60" onKeyUp="if (event.keyCode == 13) document.getElementById('apply').click()">
+<label for="filter">Filter: (regex)</label>
+<input type="text" id="filter" name="filter" size="60">
 <button onClick="changeState({filter: document.getElementById('filter').value})" id="apply">Apply</button>
 <button onClick="changeState({filter: ''})">Clear</button>
 <span id="filterResults"></span>
 </p>
 
-<table border="1">
+<table border="1" id="files">
   <thead>
     <tr>
       <th>#</th>
@@ -55,6 +63,39 @@
   </tbody>
 </table>
 
+</div>
+
+<div id="edgesview" style="display: none">
+
+<h2>Per-Edge Analysis</h2>
+
+<p>
+<label for="includerFilter">Includer (regex):</label>
+<input type="text" id="includerFilter" name="includerFilter" size="60">
+
+<label for="includedFilter">Included (regex):</label>
+<input type="text" id="includedFilter" name="includedFilter" size="60">
+
+<button onClick="changeState({includer: document.getElementById('includerFilter').value, included: document.getElementById('includedFilter').value})" id="applyEdgeFilter">Apply Filter</button>
+<button onClick="changeState({includer: '', included: ''})">Clear</button>
+<span id="edgeFilterResults"></span>
+</p>
+
+<table border="1" id="edges">
+  <thead>
+    <tr>
+      <th>#</th>
+      <th>Includer</th>
+      <th>Included</th>
+      <th colspan="2" title="The size added by this include edge being part of the build. In other words, if this include edge didn't exist, how much smaller would the build be. Also shown as percentage of the total build size.">Added Size (B) &#9432;</th>
+    </tr>
+  </thead>
+  <tbody>
+  </tbody>
+</table>
+
+</div>
+
 <hr>
 
 <p>File size does not correlate perfectly with compile time, but can serve as a rough guide to what files are slow to compile.</p>
@@ -64,6 +105,23 @@
 <script>
 "use strict";
 
+document.getElementById('filter').addEventListener('keyup', function(event) {
+  if (event.keyCode == 13) {
+    document.getElementById('apply').click();
+  }
+});
+
+document.getElementById('includerFilter').addEventListener('keyup', function(event) {
+  if (event.keyCode == 13) {
+    document.getElementById('applyEdgeFilter').click();
+  }
+});
+document.getElementById('includedFilter').addEventListener('keyup', function(event) {
+  if (event.keyCode == 13) {
+    document.getElementById('applyEdgeFilter').click();
+  }
+});
+
 function sum(arr) {
   return arr.reduce((a, b) => a + b, 0);
 }
@@ -93,26 +151,20 @@
 document.getElementById('numFiles').textContent = fmt(data.files.length);
 document.getElementById('totFileSize').textContent = fmt(totFileSize);
 
+function updateView() {
+  let s = getState();
 
-function buildRow(i, rank) {
-  return `
-<tr>
-<td><a href="#${changedStateHash({filter: '^' + regexEscape(data.files[i] + '$')})}" title="Filter on this file.">${rank + 1}</a></td>
-<td><a href="https://source.chromium.org/chromium/chromium/src/+/HEAD:${data.files[i]}">${data.files[i]}</a></td>
-<td>${fmt(data.sizes[i])}</td> <td>${(100 * data.sizes[i] / totFileSize).toFixed(2)}&nbsp;%</td>
-<td>${fmt(data.tsizes[i])}</td> <td>${(100 * data.tsizes[i] / totBuildSize).toFixed(2)}&nbsp;%</td>
-<td>${fmt(data.asizes[i])}</td> <td>${(100 * data.asizes[i] / totBuildSize).toFixed(2)}&nbsp;%</td>
-<td>${fmt(data.prevalence[i])}</td> <td>${(100 * data.prevalence[i] / numRoots).toFixed(2)}&nbsp;%</td>
-<td><a href="#${changedStateHash({filter: 'includes:' + data.files[i], sort: 'filename'})}">${fmt(data.included_by[i].length)}</a></td>
-<td><a href="#${changedStateHash({filter: 'includedby:' + data.files[i], sort: 'filename'})}">${fmt(data.includes[i].length)}</a></td>
-</tr>
-  `;
-}
+  document.getElementById('filesview').style = 'display: none';
+  document.getElementById('edgesview').style = 'display: none';
 
-function clearTable() {
-  const tbody = document.querySelector('tbody');
-  tbody.parentNode.removeChild(tbody);
-  document.getElementById('filterResults').innerHTML = '';
+  if (s.get('view') == 'files') {
+    document.getElementById('filesview').style = 'display: block';
+    buildFilesTable();
+  }
+  if (s.get('view') == 'edges') {
+    document.getElementById('edgesview').style = 'display: block';
+    buildEdgesTable();
+  }
 }
 
 function intersect(arr1, arr2) {
@@ -120,41 +172,21 @@
   return arr1.filter(x => s2.has(x));
 }
 
-function buildTable() {
-  clearTable();
+function buildFilesTable() {
   let fileNums = [...Array(data.files.length).keys()];
   const state = getState();
 
-  let filter = state.get('filter');
+  const filter = state.get('filter');
   document.getElementById('filter').value = filter;
 
   if (filter !== '') {
-    let match;
-
-    // Handle includes: operator.
-    const includesOp = new RegExp(' *includes:([^ ]*) *');
-    while (match = filter.match(includesOp)) {
-      const include = match[1];
-      const fileNum = data.files.findIndex(n => n === include);
-      fileNums = intersect(fileNums, data.included_by[fileNum]);
-      filter = filter.replace(includesOp, '');
-    }
-
-    // Handle includedby: operator.
-    const includedByOp = new RegExp(' *includedby:([^ ]*) *');
-    while (match = filter.match(includedByOp)) {
-      const filename = match[1];
-      const fileNum = data.files.findIndex(n => n === filename);
-      fileNums = intersect(fileNums, data.includes[fileNum]);
-      filter = filter.replace(includedByOp, '');
-    }
-
-
     const re = new RegExp(filter);
     fileNums = fileNums.filter(i => data.files[i].match(re));
 
     document.getElementById('filterResults').innerHTML =
         `${fmt(fileNums.length)} result${fileNums.length == 1 ? '' : 's'}.`;
+  } else {
+    document.getElementById('filterResults').innerHTML = '';
   }
 
   const sortFuncs = {
@@ -175,18 +207,108 @@
   const limit = Math.min(1000, fileNums.length);
   fileNums = fileNums.slice(0, limit);
 
-  const tbody = document.createElement('tbody');
+  function buildRow(i, rank) {
+    return `
+<tr>
+<td>${rank + 1}</td>
+<td>
+  <a href="#${changedStateHash({filter: '^' + regexEscape(data.files[i] + '$')})}">${data.files[i]}</a>
+  [<a href="https://source.chromium.org/chromium/chromium/src/+/HEAD:${data.files[i]}">cs</a>]
+</td>
+<td>${fmt(data.sizes[i])}</td> <td>${(100 * data.sizes[i] / totFileSize).toFixed(2)}&nbsp;%</td>
+<td>${fmt(data.tsizes[i])}</td> <td>${(100 * data.tsizes[i] / totBuildSize).toFixed(2)}&nbsp;%</td>
+<td>${fmt(data.asizes[i])}</td> <td>${(100 * data.asizes[i] / totBuildSize).toFixed(2)}&nbsp;%</td>
+<td>${fmt(data.prevalence[i])}</td> <td>${(100 * data.prevalence[i] / numRoots).toFixed(2)}&nbsp;%</td>
+<td><a href="#${changedStateHash({view: 'edges', includer: '', included: '^' + regexEscape(data.files[i]) + '$'})}">${fmt(data.included_by[i].length)}</a></td>
+<td><a href="#${changedStateHash({view: 'edges', included: '', includer: '^' + regexEscape(data.files[i]) + '$'})}">${fmt(data.includes[i].length)}</a></td>
+</tr>
+`;
+  }
+
+  const tbody = document.querySelector('table#files tbody');
   tbody.innerHTML = fileNums.map(buildRow).join('');
-  document.querySelector('table').appendChild(tbody);
+}
+
+
+function buildEdgesTable() {
+  const state = getState();
+  const includerFilter = state.get('includer');
+  const includedFilter = state.get('included');
+  document.getElementById('includerFilter').value = includerFilter;
+  document.getElementById('includedFilter').value = includedFilter;
+
+  const includerRe = new RegExp(includerFilter);
+  const includedRe = new RegExp(includedFilter);
+
+  let edgeSizes = [];
+  for (let src = 0; src < data.esizes.length; src++) {
+    for (let dst = 0; dst < data.esizes[src].length; dst++) {
+      const includer = src;
+      const included = data.includes[src][dst];
+      const esize = data.esizes[src][dst];
+
+      if (!data.files[includer].match(includerRe))
+        continue;
+      if (!data.files[included].match(includedRe))
+        continue;
+
+      edgeSizes.push([src, data.includes[src][dst], data.esizes[src][dst]]);
+    }
+  }
+
+  if (includerFilter == '' && includedFilter == '') {
+    document.getElementById('edgeFilterResults').innerHTML = '';
+  } else {
+    document.getElementById('edgeFilterResults').innerHTML =
+        `${fmt(edgeSizes.length)} result${edgeSizes.length == 1 ? '' : 's'}.`;
+  }
+
+  function buildRow(edgeNum) {
+    const src  = edgeSizes[edgeNum][0];
+    const dst  = edgeSizes[edgeNum][1];
+    const size = edgeSizes[edgeNum][2];
+    return `
+<tr>
+<td>${edgeNum + 1}</td>
+<td>
+  <a href="#${changedStateHash({view: 'files', filter: '^' + regexEscape(data.files[src]) + '$'})}">${data.files[src]}</a>
+  [<a href="https://source.chromium.org/chromium/chromium/src/+/HEAD:${data.files[src]}">cs</a>]
+</td>
+<td>
+  <a href="#${changedStateHash({view: 'files', filter: '^' + regexEscape(data.files[dst]) + '$'})}">${data.files[dst]}</a>
+  [<a href="https://source.chromium.org/chromium/chromium/src/+/HEAD:${data.files[dst]}">cs</a>]
+</td>
+<td>${fmt(size)}</td> <td>${(100 * size / totBuildSize).toFixed(2)}&nbsp;%</td>
+</tr>
+`;
+  }
+
+
+
+
+  edgeSizes.sort((x, y) => y[2] - x[2]);
+
+  const limit = Math.min(1000, edgeSizes.length);
+  const edgeNums = [...Array(limit).keys()];
+
+  const tbody = document.querySelector('table#edges tbody');
+  tbody.innerHTML = edgeNums.map(buildRow).join('');
+  document.querySelector('table#edges').appendChild(tbody);
 }
 
 function getState() {
   let params = new URLSearchParams(window.location.hash.substring(1));
 
+  if (!params.has('view'))
+    params.set('view', 'files');
   if (!params.has('filter'))
     params.set('filter', '');
   if (!params.has('sort'))
     params.set('sort', 'asize');
+  if (!params.has('includer'))
+    params.set('includer', '');
+  if (!params.has('included'))
+    params.set('included', '');
 
   return params;
 }
@@ -203,9 +325,9 @@
   window.location.hash = changedStateHash(changes);
 }
 
-window.onhashchange = buildTable;
+window.onhashchange = updateView;
+updateView();
 
-buildTable();
 </script>
   </body>
 </html>
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index b8255dd..a67a4b93 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -379,7 +379,7 @@
   "ash/content/file_manager/resources/file_manager_resources.grd": {
     "includes": [2518],
   },
-  "ash/content/help_app_ui/resources/help_app_resources.grd": {
+  "chromeos/components/help_app_ui/resources/help_app_resources.grd": {
     "includes": [2520],
   },
   # Both help_app_kids_magazine_bundle_resources.grd and
@@ -387,11 +387,11 @@
   # because only one of them is built depending on if src_internal is available.
   # Lower bound for number of resource ids is the number of files, which is 3 in
   # in this case (HTML, JS and CSS file).
-  "ash/content/help_app_ui/resources/prod/help_app_kids_magazine_bundle_resources.grd": {
+  "chromeos/components/help_app_ui/resources/prod/help_app_kids_magazine_bundle_resources.grd": {
     "META": {"sizes": {"includes": [5],}},
     "includes": [2530],
   },
-  "ash/content/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd": {
+  "chromeos/components/help_app_ui/resources/mock/help_app_kids_magazine_bundle_mock_resources.grd": {
     "includes": [2530],
   },
   # Both help_app_bundle_resources.grd and help_app_bundle_mock_resources.grd
@@ -399,11 +399,11 @@
   # src_internal is available. Lower bound is that we bundle ~100 images for
   # offline articles with the app, as well as strings in every language (74),
   # and bundled content in the top 25 languages (25 x 2).
-  "ash/content/help_app_ui/resources/prod/help_app_bundle_resources.grd": {
+  "chromeos/components/help_app_ui/resources/prod/help_app_bundle_resources.grd": {
     "META": {"sizes": {"includes": [300],}},  # Relies on src-internal.
     "includes": [2540],
   },
-  "ash/content/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd": {
+  "chromeos/components/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd": {
     "includes": [2540],
   },
   "chromeos/components/media_app_ui/resources/media_app_resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a79adc5..bf3dd08 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3285,6 +3285,12 @@
   <int value="10" label="Peeking To Half"/>
 </enum>
 
+<enum name="AppListUsageStateByNewUsers">
+  <int value="0" label="LAUNCHER_USED"/>
+  <int value="1" label="LAUNCHER_NOT_USED_BEFORE_DESTRUCTION"/>
+  <int value="2" label="LAUNCHER_NOT_USED_BEFORE_SWITCHING_ACCOUNTS"/>
+</enum>
+
 <enum name="AppListUserEvent">
   <int value="0" label="Impression"/>
   <int value="1" label="Launch"/>
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
index 78c42f928..d1dc34f 100644
--- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -1414,6 +1414,22 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListUsageByNewUsers"
+    enum="AppListUsageStateByNewUsers" expires_after="M99">
+  <owner>andrewxu@chromium.org</owner>
+  <owner>tbarzic@chromium.org</owner>
+  <summary>
+    Records the launcher usage state during the session started by a new user
+    (i.e. the session completing the OOBE flow). This metric is recorded in the
+    following scenarios: (1) the launcher shows and the current user is new (2)
+    the launcher has never shown before launcher is destructed. Destruction can
+    be triggered by loging out accounts, shuting down the device or system
+    crashes and meanwhile the current user is new (3) the launcher has never
+    shown when the active user has changed and the previous active user was a
+    new user.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppsCount.{AppType}" units="Apps"
     expires_after="2021-10-28">
   <owner>dominickn@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index a4b76385..427e15cb 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -12544,6 +12544,9 @@
   <suffix name="LanguageDetection" label="Language detection"/>
   <suffix name="PageTopics" label="Page topics"/>
   <suffix name="PainfulPageLoad" label="Painful page load"/>
+  <suffix name="SegmentationNewTab" label="Segmentation: New tab page user"/>
+  <suffix name="SegmentationShare" label="Segmentation: Share user"/>
+  <suffix name="SegmentationVoice" label="Segmentation: Voice user"/>
   <affected-histogram name="OptimizationGuide.IsPredictionModelValid"/>
   <affected-histogram
       name="OptimizationGuide.PredictionManager.ModelTypeChanged"/>
diff --git a/tools/metrics/histograms/split_xml.py b/tools/metrics/histograms/split_xml.py
index b814622..70a6843 100644
--- a/tools/metrics/histograms/split_xml.py
+++ b/tools/metrics/histograms/split_xml.py
@@ -19,7 +19,7 @@
 # The top level comment templates that will be formatted and added to each split
 # histograms xml.
 FIRST_TOP_LEVEL_COMMENT_TEMPLATE = """
-Copyright 2020 The Chromium Authors. All rights reserved.
+Copyright 2021 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.
 """
@@ -30,10 +30,9 @@
 For best practices on writing histogram descriptions, see
 https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md
 
-Please send CLs to chromium-metrics-reviews@google.com rather than to specific
-individuals. These CLs will be automatically reassigned to a reviewer within
-about 5 minutes. This approach helps the metrics team to load-balance incoming
-reviews. Googlers can read more about this at go/gwsq-gerrit.
+Please send CLs to individuals in the OWNERS file in the same directory as this
+xml file. If no OWNERS file exists, then send the CL to
+chromium-metrics-reviews@google.com.
 """
 # Number of times that splitting of histograms will be carried out.
 TARGET_DEPTH = 1
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 1face3c8..b3f0d36 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -10,7 +10,7 @@
         },
         "linux": {
             "hash": "5b5e6db44c3cd71a42adcad20800c9a4e35b3fd8",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/31cfc47480a7a226c3ff06143620509cbd2aa29c/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/34eb6a14728a870046c2637dbfb909d02936b84c/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/typescript/definitions/activity_log_private.d.ts b/tools/typescript/definitions/activity_log_private.d.ts
index 90b60c7..f4e944b 100644
--- a/tools/typescript/definitions/activity_log_private.d.ts
+++ b/tools/typescript/definitions/activity_log_private.d.ts
@@ -5,84 +5,87 @@
 /** @fileoverview Definitions for chrome.activityLogPrivate API. */
 // TODO(crbug.com/1203307): Auto-generate this file.
 
-import {ChromeEvent} from './chrome_event.js';
+declare namespace chrome {
+  export namespace activityLogPrivate {
 
-declare global {
-  export namespace chrome {
-    export namespace activityLogPrivate {
-
-      export enum ExtensionActivityType {
-        API_CALL = 'api_call',
-        API_EVENT = 'api_event',
-        CONTENT_SCRIPT = 'content_script',
-        DOM_ACCESS = 'dom_access',
-        DOM_EVENT = 'dom_event',
-        WEB_REQUEST = 'web_request',
-      }
-
-      export enum ExtensionActivityFilter {
-        API_CALL = 'api_call',
-        API_EVENT = 'api_event',
-        CONTENT_SCRIPT = 'content_script',
-        DOM_ACCESS = 'dom_access',
-        DOM_EVENT = 'dom_event',
-        WEB_REQUEST = 'web_request',
-        ANY = 'any',
-      }
-
-      export enum ExtensionActivityDomVerb {
-        GETTER = 'getter',
-        SETTER = 'setter',
-        METHOD = 'method',
-        INSERTED = 'inserted',
-        XHR = 'xhr',
-        WEBREQUEST = 'webrequest',
-        MODIFIED = 'modified',
-      }
-
-      export type ExtensionActivity = {
-        activityId?: string,
-        extensionId?: string, activityType: ExtensionActivityType,
-        time?: number,
-        apiCall?: string,
-        args?: string,
-        count?: number,
-        pageUrl?: string,
-        pageTitle?: string,
-        argUrl?: string,
-        other?: {
-          prerender?: boolean,
-          domVerb?: ExtensionActivityDomVerb,
-          webRequest?: string,
-          extra?: string,
-        },
-      };
-
-      export type Filter = {
-        extensionId?: string, activityType: ExtensionActivityFilter,
-        apiCall?: string,
-        pageUrl?: string,
-        argUrl?: string,
-        daysAgo?: number
-      };
-
-      export type ActivityResultSet = {
-        activities: chrome.activityLogPrivate.ExtensionActivity[],
-      };
-
-      type VoidCallback = () => void;
-
-      export function getExtensionActivities(
-          filter: Filter, callback: (result: ActivityResultSet) => void): void;
-      export function deleteActivities(
-          activityIds: string[], callback?: VoidCallback): void;
-      export function deleteActivitiesByExtension(
-          extensionId: string, callback?: VoidCallback): void;
-      export function deleteDatabase(): void;
-      export function deleteUrls(urls: string[]): void;
-
-      export const onExtensionActivity:
-          ChromeEvent<(activity: ExtensionActivity) => void>;
+    export enum ExtensionActivityType {
+      API_CALL = 'api_call',
+      API_EVENT = 'api_event',
+      CONTENT_SCRIPT = 'content_script',
+      DOM_ACCESS = 'dom_access',
+      DOM_EVENT = 'dom_event',
+      WEB_REQUEST = 'web_request',
     }
+
+    export enum ExtensionActivityFilter {
+      API_CALL = 'api_call',
+      API_EVENT = 'api_event',
+      CONTENT_SCRIPT = 'content_script',
+      DOM_ACCESS = 'dom_access',
+      DOM_EVENT = 'dom_event',
+      WEB_REQUEST = 'web_request',
+      ANY = 'any',
+    }
+
+    export enum ExtensionActivityDomVerb {
+      GETTER = 'getter',
+      SETTER = 'setter',
+      METHOD = 'method',
+      INSERTED = 'inserted',
+      XHR = 'xhr',
+      WEBREQUEST = 'webrequest',
+      MODIFIED = 'modified',
+    }
+
+    export type ExtensionActivity = {
+      activityId?: string,
+      extensionId?: string, activityType: ExtensionActivityType,
+      time?: number,
+      apiCall?: string,
+      args?: string,
+      count?: number,
+      pageUrl?: string,
+      pageTitle?: string,
+      argUrl?: string,
+      other?: {
+        prerender?: boolean,
+        domVerb?: ExtensionActivityDomVerb,
+        webRequest?: string,
+        extra?: string,
+      },
+    };
+
+    export type Filter = {
+      extensionId?: string, activityType: ExtensionActivityFilter,
+      apiCall?: string,
+      pageUrl?: string,
+      argUrl?: string,
+      daysAgo?: number
+    };
+
+    export type ActivityResultSet = {
+      activities: chrome.activityLogPrivate.ExtensionActivity[],
+    };
+
+    type VoidCallback = () => void;
+
+    export function getExtensionActivities(
+        filter: Filter, callback: (result: ActivityResultSet) => void): void;
+    export function deleteActivities(
+        activityIds: string[], callback?: VoidCallback): void;
+    export function deleteActivitiesByExtension(
+        extensionId: string, callback?: VoidCallback): void;
+    export function deleteDatabase(): void;
+    export function deleteUrls(urls: string[]): void;
+
+    // This is a workaround for the fact that importing other .d.ts files does
+    // not work. ChromeEvent is also used elsewhere so should be in its own
+    // file.
+    export interface ChromeEvent<ListenerType> {
+      addListener(listener: ListenerType): void;
+      removeListener(listener: ListenerType): void;
+    }
+
+    export const onExtensionActivity: ChromeEvent<(activity: ExtensionActivity) => void>;
   }
 }
diff --git a/tools/typescript/definitions/bookmark_manager_private.d.ts b/tools/typescript/definitions/bookmark_manager_private.d.ts
index e832a92..c9fd4a35 100644
--- a/tools/typescript/definitions/bookmark_manager_private.d.ts
+++ b/tools/typescript/definitions/bookmark_manager_private.d.ts
@@ -5,53 +5,41 @@
 /** @fileoverview Definitions for chrome.bookmarkManagerPrivate API. */
 // TODO(crbug.com/1203307): Auto-generate this file.
 
-import {ChromeEvent} from './chrome_event.js';
-
-declare global {
-  export namespace chrome {
-    export namespace bookmarkManagerPrivate {
-      export interface BookmarkNodeDataElement {
-        id?: string;
-        parentId?: string;
-        title: string;
-        url?: string;
-        children: BookmarkNodeDataElement[];
-      }
-
-      export interface BookmarkNodeData {
-        sameProfile: boolean;
-        elements: BookmarkNodeDataElement[];
-      }
-
-      export function copy(idList: string[], callback: () => void): void;
-      export function cut(idList: string[], callback?: () => void): void;
-      export function paste(
-          parentId: string, selectedIdList?: string[],
-          callback?: () => void): void;
-      export function canPaste(
-          parentId: string, callback: (p1: boolean) => void): void;
-      export function sortChildren(parentId: string): void;
-      export function startDrag(
-          idList: string[], dragNodeIndex: number, isFromTouch: boolean,
-          x: number, y: number): void;
-      export function drop(
-          parentId: string, index?: number, callback?: () => void): void;
-      export function getSubtree(
-          id: string, foldersOnly: boolean,
-          callback: (p1: chrome.bookmarks.BookmarkTreeNode[]) => void): void;
-      export function removeTrees(idList: string[], callback?: () => void):
-          void;
-      export function undo(): void;
-      export function redo(): void;
-
-      type DragData = {
-        elements: chrome.bookmarks.BookmarkTreeNode[]|null;
-        sameProfile: boolean;
-      };
-
-      export const onDragEnter: ChromeEvent<(p1: DragData) => void>;
-      export const onDragLeave: ChromeEvent<() => void>;
-      export const onDrop: ChromeEvent<() => void>;
+declare namespace chrome {
+  export namespace bookmarkManagerPrivate {
+    export interface BookmarkNodeDataElement {
+      id?: string;
+      parentId?: string;
+      title: string;
+      url?: string;
+      children: BookmarkNodeDataElement[];
     }
+
+    export interface BookmarkNodeData {
+      sameProfile: boolean,
+      elements: BookmarkNodeDataElement[];
+    }
+
+    export function copy(idList: string[], callback: () => void): void;
+    export function cut(idList: string[], callback?: () => void): void;
+    export function paste(parentId: string, selectedIdList?: string[],
+                          callback?: () => void): void;
+    export function canPaste(
+        parentId: string, callback: (boolean) => void): void;
+    export function sortChildren(parentId: string): void;
+    export function startDrag(idList: string[], dragNodeIndex: number,
+                              isFromTouch: boolean, x: number, y: number): void;
+    export function drop(parentId: string, index?: number,
+                         callback?: () => void): void;
+    export function getSubtree(
+        id: string, foldersOnly: boolean,
+        callback: (p1: chrome.bookmarks.BookmarkTreeNode[]) => void): void;
+    export function removeTrees(idList: string[], callback?: () => void): void;
+    export function undo(): void;
+    export function redo(): void;
+
+    export const onDragEnter: chrome.bookmarks.ChromeEvent<() => void>;
+    export const onDragLeave: chrome.bookmarks.ChromeEvent<() => void>;
+    export const onDrop: chrome.bookmarks.ChromeEvent<() => void>;
   }
 }
diff --git a/tools/typescript/definitions/bookmarks.d.ts b/tools/typescript/definitions/bookmarks.d.ts
index b775b239..9a963d3 100644
--- a/tools/typescript/definitions/bookmarks.d.ts
+++ b/tools/typescript/definitions/bookmarks.d.ts
@@ -5,120 +5,123 @@
 /** @fileoverview Definitions for chrome.bookmarks API. */
 // TODO(crbug.com/1203307): Auto-generate this file.
 
-import {ChromeEvent} from './chrome_event.js';
-
-declare global {
-  export namespace chrome {
-    export namespace bookmarks {
-      export enum BookmarkTreeNodeUnmodifiable {
-        MANAGED = 'managed',
-      }
-
-      export interface BookmarkTreeNode {
-        id: string;
-        parentId?: string;
-        index?: number;
-        url?: string;
-        title: string;
-        dateAdded?: number;
-        dateGroupModified?: number;
-        unmodifiable?: BookmarkTreeNodeUnmodifiable;
-        children?: BookmarkTreeNode[];
-      }
-
-      export interface CreateDetails {
-        parentId?: string|null;
-        index?: number;
-        title?: string;
-        url?: string;
-      }
-
-      export const MAX_WRITE_OPERATIONS_PER_HOUR: number;
-      export const MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE: number;
-
-      export function get(
-          idOrIdList: string|string[],
-          callback: (p1: BookmarkTreeNode[]) => void): void;
-
-      export function getChildren(
-          id: string, callback: (p1: BookmarkTreeNode[]) => void): void;
-
-      export function getRecent(
-          numberOfItems: number,
-          callback: (p1: BookmarkTreeNode[]) => void): void;
-
-      export function getTree(callback: (p1: BookmarkTreeNode[]) => void): void;
-
-      export function getSubTree(
-          id: string, callback: (p1: BookmarkTreeNode[]) => void): void;
-
-      export function search(
-          query: string|{
-            query: string | undefined,
-            url: string|undefined,
-            title: string|undefined
-          },
-          callback: (p1: BookmarkTreeNode[]) => void): void;
-
-      export function create(
-          bookmark: CreateDetails,
-          callback?: (p1: BookmarkTreeNode) => void): void;
-
-      export function move(
-          id: string,
-          destination: {parentId: string|undefined, index: number|undefined},
-          callback?: (p1: BookmarkTreeNode) => void): void;
-
-      export function update(
-          id: string, changes: {title?: string, url?: string},
-          callback?: (p1: BookmarkTreeNode) => void): void;
-
-      export function remove(id: string, callback?: () => void): void;
-      export function removeTree(id: string, callback?: () => void): void;
-      function _import(callback?: () => void): void;
-      function _export(callback?: () => void): void;
-      export { _import as import }
-      export { _export as export }
-
-      export const onCreated:
-          ChromeEvent<(id: string, bookmark: BookmarkTreeNode) => void>;
-
-      export interface ChangeInfo {
-        title: string;
-        url: string;
-      }
-
-      export const onChanged:
-          ChromeEvent<(id: string, changeInfo: ChangeInfo) => void>;
-
-      export interface ReorderInfo {
-        childIds: string[],
-      }
-
-      export const onChildrenReordered:
-          ChromeEvent<(id: string, reorderInfo: ReorderInfo) => void>;
-
-      export interface RemoveInfo {
-        index: number;
-        node: BookmarkTreeNode;
-        parentId: string;
-      }
-
-      export const onRemoved:
-          ChromeEvent<(id: string, removeInfo: RemoveInfo) => void>;
-
-      export interface MoveInfo {
-        index: number;
-        oldIndex: number;
-        oldParentId: string;
-        parentId: string;
-      }
-
-      export const onMoved:
-          ChromeEvent<(id: string, moveInfo: MoveInfo) => void>;
-
-      export const onImportEnded: ChromeEvent<() => void>;
-      export const onImportBegan: ChromeEvent<() => void>;
+declare namespace chrome {
+  export namespace bookmarks {
+    export enum BookmarkTreeNodeUnmodifiable {
+      MANAGED = 'managed',
     }
+
+    export interface BookmarkTreeNode {
+      id: string;
+      parentId?: string;
+      index?: number;
+      url?: string;
+      title: string;
+      dateAdded?: number;
+      dateGroupModified?: number;
+      unmodifiable?: BookmarkTreeNodeUnmodifiable;
+      children?: BookmarkTreeNode[];
+    }
+
+    export interface CreateDetails {
+      parentId?: string;
+      index?: number;
+      title?: string;
+      url?: string;
+    }
+
+    export const MAX_WRITE_OPERATIONS_PER_HOUR: number;
+    export const MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE: number;
+
+    export function get(
+        idOrIdList: string|string[],
+        callback: (p1: BookmarkTreeNode[]) => void): void;
+
+    export function getChildren(
+        id: string, callback: (p1: BookmarkTreeNode[]) => void): void;
+
+    export function getRecent(
+        numberOfItems: number,
+        callback: (p1: BookmarkTreeNode[]) => void): void;
+
+    export function getTree(callback: (p1: BookmarkTreeNode[]) => void): void;
+
+    export function getSubTree(
+        id: string, callback: (p1: BookmarkTreeNode[]) => void): void;
+
+    export function search(
+        query: string|{
+          query: string | undefined,
+          url: string|undefined,
+          title: string|undefined
+        },
+        callback: (p1: BookmarkTreeNode[]) => void): void;
+
+    export function create(
+        bookmark: CreateDetails,
+        callback?: (p1: BookmarkTreeNode) => void): void;
+
+    export function move(
+        id: string,
+        destination: {parentId: string|undefined, index: number|undefined},
+        callback?: (p1: BookmarkTreeNode) => void): void;
+
+    export function update(
+        id: string, changes: {title?: string, url?: string},
+        callback?: (p1: BookmarkTreeNode) => void): void;
+
+    export function remove(id: string, callback?: () => void): void;
+    export function removeTree(id: string, callback?: () => void): void;
+    function _import(callback?: () => void): void;
+    function _export(callback?: () => void): void;
+    export {_import as import}
+    export {_export as export}
+
+    // This is a workaround for the fact that importing other .d.ts files does
+    // not work. ChromeEvent is also used elsewhere so should be in its own
+    // file.
+    export interface ChromeEvent<ListenerType> {
+      addListener(listener: ListenerType): void;
+      removeListener(listener: ListenerType): void;
+    }
+
+    export const onCreated:
+        ChromeEvent<(id: string, bookmark: BookmarkTreeNode) => void>;
+
+    export interface ChangeInfo {
+      title: string,
+      url: string,
+    }
+
+    export const onChanged:
+        ChromeEvent<(id: string, changeInfo: ChangeInfo) => void>;
+
+    export interface ReorderInfo {
+      childIds: string[],
+    }
+
+    export const onChildrenReordered:
+        ChromeEvent<(id: string, reorderInfo: ReorderInfo) => void>;
+
+    export interface RemoveInfo {
+      index: number,
+      node: BookmarkTreeNode,
+      parentId: string,
+    }
+
+    export const onRemoved:
+        ChromeEvent<(id: string, removeInfo: RemoveInfo) => void>;
+
+    export interface MoveInfo {
+      index: number,
+      oldIndex: number,
+      oldParentId: string,
+      parentId: string,
+    }
+
+    export const onMoved: ChromeEvent<(id: string, moveInfo: MoveInfo) => void>;
+
+    export const onImportEnded: ChromeEvent<() => void>;
+    export const onImportBegan: ChromeEvent<() => void>;
   }
 }
diff --git a/tools/typescript/definitions/chrome_event.d.ts b/tools/typescript/definitions/chrome_event.d.ts
deleted file mode 100644
index 0ce7cf1..0000000
--- a/tools/typescript/definitions/chrome_event.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2021 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.
-
-export interface ChromeEvent<ListenerType> {
-  addListener(listener: ListenerType): void;
-  removeListener(listener: ListenerType): void;
-}
diff --git a/tools/typescript/definitions/developer_private.d.ts b/tools/typescript/definitions/developer_private.d.ts
index 5a1930ad..2edd0c1 100644
--- a/tools/typescript/definitions/developer_private.d.ts
+++ b/tools/typescript/definitions/developer_private.d.ts
@@ -5,430 +5,433 @@
 /** @fileoverview Definitions for chrome.developerPrivate API */
 // TODO(crbug.com/1203307): Auto-generate this file.
 
-import {ChromeEvent} from './chrome_event.js';
+declare namespace chrome {
+  export namespace developerPrivate {
 
-declare global {
-  export namespace chrome {
-    export namespace developerPrivate {
-
-      export enum ItemType {
-        HOSTED_APP = 'hosted_app',
-        PACKAGED_APP = 'packaged_app',
-        LEGACY_PACKAGED_APP = 'legacy_packaged_app',
-        EXTENSION = 'extension',
-        THEME = 'theme',
-      }
-
-      export type ItemInspectView = {
-        path: string,
-        render_process_id: number,
-        render_view_id: number,
-        incognito: boolean,
-        generatedBackgroundPage: boolean,
-      };
-
-      export type InstallWarning = {
-        message: string,
-      };
-
-      export enum ExtensionType {
-        HOSTED_APP = 'HOSTED_APP',
-        PLATFORM_APP = 'PLATFORM_APP',
-        LEGACY_PACKAGED_APP = 'LEGACY_PACKAGED_APP',
-        EXTENSION = 'EXTENSION',
-        THEME = 'THEME',
-        SHARED_MODULE = 'SHARED_MODULE',
-      }
-
-      export enum Location {
-        FROM_STORE = 'FROM_STORE',
-        UNPACKED = 'UNPACKED',
-        THIRD_PARTY = 'THIRD_PARTY',
-        UNKNOWN = 'UNKNOWN',
-      }
-
-      export enum ViewType {
-        APP_WINDOW = 'APP_WINDOW',
-        BACKGROUND_CONTENTS = 'BACKGROUND_CONTENTS',
-        COMPONENT = 'COMPONENT',
-        EXTENSION_BACKGROUND_PAGE = 'EXTENSION_BACKGROUND_PAGE',
-        EXTENSION_DIALOG = 'EXTENSION_DIALOG',
-        EXTENSION_GUEST = 'EXTENSION_GUEST',
-        EXTENSION_POPUP = 'EXTENSION_POPUP',
-        EXTENSION_SERVICE_WORKER_BACKGROUND =
-            'EXTENSION_SERVICE_WORKER_BACKGROUND',
-        TAB_CONTENTS = 'TAB_CONTENTS',
-      }
-
-      export enum ErrorType {
-        MANIFEST = 'MANIFEST',
-        RUNTIME = 'RUNTIME',
-      }
-
-      export enum ErrorLevel {
-        LOG = 'LOG',
-        WARN = 'WARN',
-        ERROR = 'ERROR',
-      }
-
-      export enum ExtensionState {
-        ENABLED = 'ENABLED',
-        DISABLED = 'DISABLED',
-        TERMINATED = 'TERMINATED',
-        BLACKLISTED = 'BLACKLISTED',
-      }
-
-      export enum ComandScope {
-        GLOBAL = 'GLOBAL',
-        CHROME = 'CHROME',
-      }
-
-      export type GetExtensionsInfoOptions = {
-        includeDisabled?: boolean,
-        includeTerminated?: boolean,
-      };
-
-      export enum CommandScope {
-        GLOBAL = 'GLOBAL',
-        CHROME = 'CHROME',
-      }
-
-      export type AccessModifier = {
-        isEnabled: boolean,
-        isActive: boolean,
-      };
-
-      export type StackFrame = {
-        lineNumber: number,
-        columnNumber: number,
-        url: string,
-        functionName: string,
-      };
-
-      export type ManifestError = {
-        type: ErrorType,
-        extensionId: string,
-        fromIncognito: boolean,
-        source: string,
-        message: string,
-        id: number,
-        manifestKey: string,
-        manifestSpecific?: string,
-      };
-
-      export type RuntimeError = {
-        type: ErrorType,
-        extensionId: string,
-        fromIncognito: boolean,
-        source: string,
-        message: string,
-        id: number,
-        severity: ErrorLevel,
-        contextUrl: string,
-        occurrences: number,
-        renderViewId: number,
-        renderProcessId: number,
-        canInspect: boolean,
-        stackTrace: StackFrame[],
-      };
-
-      export type DisableReasons = {
-        suspiciousInstall: boolean,
-        corruptInstall: boolean,
-        updateRequired: boolean,
-        blockedByPolicy: boolean,
-        reloading: boolean,
-        custodianApprovalRequired: boolean,
-        parentDisabledPermissions: boolean,
-      };
-
-      export type OptionsPage = {
-        openInTab: boolean,
-        url: string,
-      };
-
-      export type HomePage = {
-        url: string,
-        specified: boolean,
-      };
-
-      export type ExtensionView = {
-        url: string,
-        renderProcessId: number,
-        renderViewId: number,
-        incognito: boolean,
-        isIframe: boolean,
-        type: ViewType,
-      };
-
-      export enum HostAccess {
-        ON_CLICK = 'ON_CLICK',
-        ON_SPECIFIC_SITES = 'ON_SPECIFIC_SITES',
-        ON_ALL_SITES = 'ON_ALL_SITES',
-      }
-
-      export type ControlledInfo = {
-        text: string,
-      };
-
-      export type Command = {
-        description: string,
-        keybinding: string,
-        name: string,
-        isActive: boolean,
-        scope: CommandScope,
-        isExtensionAction: boolean,
-      };
-
-      export type DependentExtension = {
-        id: string,
-        name: string,
-      };
-
-      export type Permission = {
-        message: string,
-        submessages: string[],
-      };
-
-      export type SiteControl = {
-        host: string,
-        granted: boolean,
-      };
-
-      export type RuntimeHostPermissions = {
-        hasAllHosts: boolean,
-        hostAccess: HostAccess,
-        hosts: chrome.developerPrivate.SiteControl[],
-      };
-
-      export type Permissions = {
-        simplePermissions: chrome.developerPrivate.Permission[],
-        runtimeHostPermissions?: RuntimeHostPermissions,
-      };
-
-      export type ExtensionInfo = {
-        blacklistText?: string,
-        commands: Command[],
-        controlledInfo?: ControlledInfo,
-        dependentExtensions: DependentExtension[],
-        description: string,
-        disableReasons: DisableReasons,
-        errorCollection: AccessModifier,
-        fileAccess: AccessModifier,
-        homePage: HomePage,
-        iconUrl: string,
-        id: string,
-        incognitoAccess: AccessModifier,
-        installWarnings: string[],
-        launchUrl?: string, location: Location,
-        locationText?: string,
-        manifestErrors: ManifestError[],
-        manifestHomePageUrl: string,
-        mustRemainInstalled: boolean,
-        name: string,
-        offlineEnabled: boolean,
-        optionsPage?: OptionsPage,
-        path?: string,
-        permissions: Permissions,
-        prettifiedPath?: string,
-        runtimeErrors: RuntimeError[],
-        runtimeWarnings: string[],
-        state: ExtensionState,
-        type: ExtensionType,
-        updateUrl: string,
-        userMayModify: boolean,
-        version: string,
-        views: ExtensionView[],
-        webStoreUrl: string,
-        showSafeBrowsingAllowlistWarning: boolean,
-      };
-
-      export type ProfileInfo = {
-        canLoadUnpacked: boolean,
-        inDeveloperMode: boolean,
-        isDeveloperModeControlledByPolicy: boolean,
-        isIncognitoAvailable: boolean,
-        isSupervised: boolean,
-      };
-
-      export type ExtensionConfigurationUpdate = {
-        extensionId: string,
-        fileAccess?: boolean,
-        incognitoAccess?: boolean,
-        errorCollection?: boolean,
-        hostAccess?: HostAccess,
-      };
-
-      export type ProfileConfigurationUpdate = {
-        inDeveloperMode: boolean,
-      };
-
-      export type ExtensionCommandUpdate = {
-        extensionId: string,
-        commandName: string,
-        scope?: CommandScope,
-        keybinding?: string,
-      };
-
-      export type ReloadOptions = {
-        failQuietly?: boolean,
-        populateErrorForUnpacked?: boolean,
-      };
-
-      export type LoadUnpackedOptions = {
-        failQuietly?: boolean,
-        populateError?: boolean,
-        retryGuid?: string,
-        useDraggedPath?: boolean,
-      };
-
-      export enum PackStatus {
-        SUCCESS = 'SUCCESS',
-        ERROR = 'ERROR',
-        WARNING = 'WARNING',
-      }
-
-      export enum FileType {
-        LOAD = 'LOAD',
-        PEM = 'PEM',
-      }
-
-      export enum SelectType {
-        FILE = 'FILE',
-        FOLDER = 'FOLDER',
-      }
-
-      export enum EventType {
-        INSTALLED = 'INSTALLED',
-        UNINSTALLED = 'UNINSTALLED',
-        LOADED = 'LOADED',
-        UNLOADED = 'UNLOADED',
-        VIEW_REGISTERED = 'VIEW_REGISTERED',
-        VIEW_UNREGISTERED = 'VIEW_UNREGISTERED',
-        ERROR_ADDED = 'ERROR_ADDED',
-        ERRORS_REMOVED = 'ERRORS_REMOVED',
-        PREFS_CHANGED = 'PREFS_CHANGED',
-        WARNINGS_CHANGED = 'WARNINGS_CHANGED',
-        COMMAND_ADDED = 'COMMAND_ADDED',
-        COMMAND_REMOVED = 'COMMAND_REMOVED',
-        PERMISSIONS_CHANGED = 'PERMISSIONS_CHANGED',
-        SERVICE_WORKER_STARTED = 'SERVICE_WORKER_STARTED',
-        SERVICE_WORKER_STOPPED = 'SERVICE_WORKER_STOPPED',
-      }
-
-      export type PackDirectoryResponse = {
-        message: string,
-        item_path: string,
-        pem_path: string,
-        override_flags: number,
-        status: PackStatus,
-      };
-
-      export type EventData = {
-        event_type: EventType,
-        item_id: string,
-        extensionInfo?: ExtensionInfo,
-      };
-
-      export type ErrorFileSource = {
-        beforeHighlight: string,
-        highlight: string,
-        afterHighlight: string,
-      };
-
-      export type LoadError = {
-        error: string,
-        path: string,
-        source?: ErrorFileSource, retryGuid: string,
-      };
-
-      export type RequestFileSourceProperties = {
-        extensionId: string,
-        pathSuffix: string,
-        message: string,
-        manifestKey?: string,
-        manifestSpecific?: string,
-        lineNumber?: number,
-      };
-
-      export type RequestFileSourceResponse = {
-        highlight: string,
-        beforeHighlight: string,
-        afterHighlight: string,
-        title: string,
-        message: string
-      };
-
-      export type OpenDevToolsProperties = {
-        extensionId?: string, renderViewId: number, renderProcessId: number,
-        isServiceWorker?: boolean,
-        incognito?: boolean,
-        url?: string,
-        lineNumber?: number,
-        columnNumber?: number
-      };
-
-      export type DeleteExtensionErrorsProperties = {
-        extensionId: string,
-        errorIds?: number[],
-        type?: ErrorType,
-      };
-
-      type VoidCallback = () => void;
-      type StringCallback = (s: string) => void;
-
-      export function addHostPermission(
-          extensionId: string, host: string, callback: VoidCallback): void;
-      export function autoUpdate(callback: VoidCallback): void;
-      export function choosePath(
-          selectType: SelectType, fileType: FileType,
-          callback: StringCallback): void;
-      export function deleteExtensionErrors(
-          properties: DeleteExtensionErrorsProperties,
-          callback?: VoidCallback): void;
-      export function getExtensionsInfo(
-          options: GetExtensionsInfoOptions,
-          callback: (info: ExtensionInfo) => void): void;
-      export function getExtensionSize(id: string, callback: StringCallback):
-          void;
-      export function getProfileConfiguration(
-          callback: (info: ProfileInfo) => void): void;
-      export function installDroppedFile(callback?: VoidCallback): void;
-      export function loadUnpacked(
-          options: LoadUnpackedOptions,
-          callback: (error?: LoadError) => void): void;
-      export function notifyDragInstallInProgress(): void;
-      export function openDevTools(
-          properties: OpenDevToolsProperties, callback?: VoidCallback): void;
-      export function packDirectory(
-          path: string, privateKeyPath: string, flags?: number,
-          callback?: (response: PackDirectoryResponse) => void): void;
-      export function reload(
-          extensionId: string, options?: ReloadOptions,
-          callback?: (error?: LoadError) => void): void;
-      export function removeHostPermission(
-          extensionId: string, host: string, callback: VoidCallback): void;
-      export function repairExtension(
-          extensionId: string, callback?: VoidCallback): void;
-      export function requestFileSource(
-          properties: RequestFileSourceProperties,
-          callback: (response: RequestFileSourceResponse) => void): void;
-      export function setShortcutHandlingSuspended(
-          isSuspended: boolean, callback?: VoidCallback): void;
-      export function showOptions(extensionId: string, callback?: VoidCallback):
-          void;
-      export function showPath(extensionId: string, callback?: VoidCallback):
-          void;
-      export function updateExtensionCommand(
-          update: ExtensionCommandUpdate, callback?: VoidCallback): void;
-      export function updateExtensionConfiguration(
-          update: ExtensionConfigurationUpdate, callback?: VoidCallback): void;
-      export function updateProfileConfiguration(
-          update: ProfileConfigurationUpdate, callback?: VoidCallback): void;
-
-      export const onItemStateChanged: ChromeEvent<(data: EventData) => void>;
-      export const onProfileStateChanged:
-          ChromeEvent<(info: ProfileInfo) => void>;
+    export enum ItemType {
+      HOSTED_APP = 'hosted_app',
+      PACKAGED_APP = 'packaged_app',
+      LEGACY_PACKAGED_APP = 'legacy_packaged_app',
+      EXTENSION = 'extension',
+      THEME = 'theme',
     }
+
+    export type ItemInspectView = {
+      path: string,
+      render_process_id: number,
+      render_view_id: number,
+      incognito: boolean,
+      generatedBackgroundPage: boolean,
+    };
+
+    export type InstallWarning = {
+      message: string,
+    };
+
+    export enum ExtensionType {
+      HOSTED_APP = 'HOSTED_APP',
+      PLATFORM_APP = 'PLATFORM_APP',
+      LEGACY_PACKAGED_APP = 'LEGACY_PACKAGED_APP',
+      EXTENSION = 'EXTENSION',
+      THEME = 'THEME',
+      SHARED_MODULE = 'SHARED_MODULE',
+    }
+
+    export enum Location {
+      FROM_STORE = 'FROM_STORE',
+      UNPACKED = 'UNPACKED',
+      THIRD_PARTY = 'THIRD_PARTY',
+      UNKNOWN = 'UNKNOWN',
+    }
+
+    export enum ViewType {
+      APP_WINDOW = 'APP_WINDOW',
+      BACKGROUND_CONTENTS = 'BACKGROUND_CONTENTS',
+      COMPONENT = 'COMPONENT',
+      EXTENSION_BACKGROUND_PAGE = 'EXTENSION_BACKGROUND_PAGE',
+      EXTENSION_DIALOG = 'EXTENSION_DIALOG',
+      EXTENSION_GUEST = 'EXTENSION_GUEST',
+      EXTENSION_POPUP = 'EXTENSION_POPUP',
+      EXTENSION_SERVICE_WORKER_BACKGROUND =
+          'EXTENSION_SERVICE_WORKER_BACKGROUND',
+      TAB_CONTENTS = 'TAB_CONTENTS',
+    }
+
+    export enum ErrorType {
+      MANIFEST = 'MANIFEST',
+      RUNTIME = 'RUNTIME',
+    }
+
+    export enum ErrorLevel {
+      LOG = 'LOG',
+      WARN = 'WARN',
+      ERROR = 'ERROR',
+    }
+
+    export enum ExtensionState {
+      ENABLED = 'ENABLED',
+      DISABLED = 'DISABLED',
+      TERMINATED = 'TERMINATED',
+      BLACKLISTED = 'BLACKLISTED',
+    }
+
+    export enum ComandScope {
+      GLOBAL = 'GLOBAL',
+      CHROME = 'CHROME',
+    }
+
+    export type GetExtensionsInfoOptions = {
+      includeDisabled?: boolean,
+      includeTerminated?: boolean,
+    };
+
+    export enum CommandScope {
+      GLOBAL = 'GLOBAL',
+      CHROME = 'CHROME',
+    }
+
+    export type AccessModifier = {
+      isEnabled: boolean,
+      isActive: boolean,
+    };
+
+    export type StackFrame = {
+      lineNumber: number,
+      columnNumber: number,
+      url: string,
+      functionName: string,
+    };
+
+    export type ManifestError = {
+      type: ErrorType,
+      extensionId: string,
+      fromIncognito: boolean,
+      source: string,
+      message: string,
+      id: number,
+      manifestKey: string,
+      manifestSpecific?: string,
+    };
+
+    export type RuntimeError = {
+      type: ErrorType,
+      extensionId: string,
+      fromIncognito: boolean,
+      source: string,
+      message: string,
+      id: number,
+      severity: ErrorLevel,
+      contextUrl: string,
+      occurrences: number,
+      renderViewId: number,
+      renderProcessId: number,
+      canInspect: boolean,
+      stackTrace: StackFrame[],
+    };
+
+    export type DisableReasons = {
+      suspiciousInstall: boolean,
+      corruptInstall: boolean,
+      updateRequired: boolean,
+      blockedByPolicy: boolean,
+      reloading: boolean,
+      custodianApprovalRequired: boolean,
+      parentDisabledPermissions: boolean,
+    };
+
+    export type OptionsPage = {
+      openInTab: boolean,
+      url: string,
+    };
+
+    export type HomePage = {
+       url: string,
+       specified: boolean,
+    };
+
+    export type ExtensionView = {
+      url: string,
+      renderProcessId: number,
+      renderViewId: number,
+      incognito: boolean,
+      isIframe: boolean,
+      type: ViewType,
+    };
+
+    export enum HostAccess {
+      ON_CLICK = 'ON_CLICK',
+      ON_SPECIFIC_SITES = 'ON_SPECIFIC_SITES',
+      ON_ALL_SITES = 'ON_ALL_SITES',
+    }
+
+    export type ControlledInfo = {
+      text: string,
+    };
+
+    export type Command = {
+      description: string,
+      keybinding: string,
+      name: string,
+      isActive: boolean,
+      scope: CommandScope,
+      isExtensionAction: boolean,
+    };
+
+    export type DependentExtension = {
+      id: string,
+      name: string,
+    };
+
+    export type Permission = {
+      message: string,
+      submessages: string[],
+    };
+
+    export type SiteControl = {
+      host: string,
+      granted: boolean,
+    };
+
+    export type RuntimeHostPermissions = {
+       hasAllHosts: boolean,
+       hostAccess: HostAccess,
+       hosts: chrome.developerPrivate.SiteControl[],
+    };
+
+    export type Permissions = {
+      simplePermissions: chrome.developerPrivate.Permission[],
+      runtimeHostPermissions?: RuntimeHostPermissions,
+    };
+
+    export type ExtensionInfo = {
+      blacklistText?: string,
+      commands: Command[],
+      controlledInfo?: ControlledInfo,
+      dependentExtensions: DependentExtension[],
+      description: string,
+      disableReasons: DisableReasons,
+      errorCollection: AccessModifier,
+      fileAccess: AccessModifier,
+      homePage: HomePage,
+      iconUrl: string,
+      id: string,
+      incognitoAccess: AccessModifier,
+      installWarnings: string[],
+      launchUrl?: string, location: Location,
+      locationText?: string,
+      manifestErrors: ManifestError[],
+      manifestHomePageUrl: string,
+      mustRemainInstalled: boolean,
+      name: string,
+      offlineEnabled: boolean,
+      optionsPage?: OptionsPage,
+      path?: string,
+      permissions: Permissions,
+      prettifiedPath?: string,
+      runtimeErrors: RuntimeError[],
+      runtimeWarnings: string[],
+      state: ExtensionState,
+      type: ExtensionType,
+      updateUrl: string,
+      userMayModify: boolean,
+      version: string,
+      views: ExtensionView[],
+      webStoreUrl: string,
+      showSafeBrowsingAllowlistWarning: boolean,
+    };
+
+    export type ProfileInfo = {
+      canLoadUnpacked: boolean,
+      inDeveloperMode: boolean,
+      isDeveloperModeControlledByPolicy: boolean,
+      isIncognitoAvailable: boolean,
+      isSupervised: boolean,
+    };
+
+    export type ExtensionConfigurationUpdate = {
+      extensionId: string,
+      fileAccess?: boolean,
+      incognitoAccess?: boolean,
+      errorCollection?: boolean,
+      hostAccess?: HostAccess,
+    };
+
+    export type ProfileConfigurationUpdate = {
+      inDeveloperMode: boolean,
+    };
+
+    export type ExtensionCommandUpdate = {
+      extensionId: string,
+      commandName: string,
+      scope?: CommandScope,
+      keybinding?: string,
+    };
+
+    export type ReloadOptions = {
+      failQuietly?: boolean,
+      populateErrorForUnpacked?: boolean,
+    };
+
+    export type LoadUnpackedOptions = {
+      failQuietly?: boolean,
+      populateError?: boolean,
+      retryGuid?: string,
+      useDraggedPath?: boolean,
+    };
+
+    export enum PackStatus {
+      SUCCESS = 'SUCCESS',
+      ERROR = 'ERROR',
+      WARNING = 'WARNING',
+    }
+
+    export enum FileType {
+      LOAD = 'LOAD',
+      PEM = 'PEM',
+    }
+
+    export enum SelectType {
+      FILE = 'FILE',
+      FOLDER = 'FOLDER',
+    }
+
+    export enum EventType {
+      INSTALLED = 'INSTALLED',
+      UNINSTALLED = 'UNINSTALLED',
+      LOADED = 'LOADED',
+      UNLOADED = 'UNLOADED',
+      VIEW_REGISTERED = 'VIEW_REGISTERED',
+      VIEW_UNREGISTERED = 'VIEW_UNREGISTERED',
+      ERROR_ADDED = 'ERROR_ADDED',
+      ERRORS_REMOVED = 'ERRORS_REMOVED',
+      PREFS_CHANGED = 'PREFS_CHANGED',
+      WARNINGS_CHANGED = 'WARNINGS_CHANGED',
+      COMMAND_ADDED = 'COMMAND_ADDED',
+      COMMAND_REMOVED = 'COMMAND_REMOVED',
+      PERMISSIONS_CHANGED = 'PERMISSIONS_CHANGED',
+      SERVICE_WORKER_STARTED = 'SERVICE_WORKER_STARTED',
+      SERVICE_WORKER_STOPPED = 'SERVICE_WORKER_STOPPED',
+    }
+
+    export type PackDirectoryResponse = {
+      message: string,
+      item_path: string,
+      pem_path: string,
+      override_flags: number,
+      status: PackStatus,
+    };
+
+    export type EventData = {
+      event_type: EventType,
+      item_id: string,
+      extensionInfo?: ExtensionInfo,
+    };
+
+    export type ErrorFileSource = {
+      beforeHighlight: string,
+      highlight: string,
+      afterHighlight: string,
+    };
+
+    export type LoadError = {
+      error: string,
+      path: string,
+      source?: ErrorFileSource, retryGuid: string,
+    };
+
+    export type RequestFileSourceProperties = {
+      extensionId: string,
+      pathSuffix: string,
+      message: string,
+      manifestKey?: string,
+      manifestSpecific?: string,
+      lineNumber?: number,
+    };
+
+    export type RequestFileSourceResponse = {
+      highlight: string,
+      beforeHighlight: string,
+      afterHighlight: string,
+      title: string,
+      message: string
+    };
+
+    export type OpenDevToolsProperties = {
+      extensionId?: string, renderViewId: number, renderProcessId: number,
+      isServiceWorker?: boolean,
+      incognito?: boolean,
+      url?: string,
+      lineNumber?: number,
+      columnNumber?: number
+    };
+
+    export type DeleteExtensionErrorsProperties = {
+      extensionId: string,
+      errorIds?: number[],
+      type?: ErrorType,
+    };
+
+    type VoidCallback = () => void;
+    type StringCallback = (s: string) => void;
+
+    export function addHostPermission(
+        extensionId: string, host: string, callback: VoidCallback): void;
+    export function autoUpdate(callback: VoidCallback): void;
+    export function choosePath(
+        selectType: SelectType, fileType: FileType,
+        callback: StringCallback): void;
+    export function deleteExtensionErrors(
+        properties: DeleteExtensionErrorsProperties,
+        callback?: VoidCallback): void;
+    export function getExtensionsInfo(
+        options: GetExtensionsInfoOptions,
+        callback: (info: ExtensionInfo) => void): void;
+    export function getExtensionSize(id: string, callback: StringCallback):
+        void;
+    export function getProfileConfiguration(
+        callback: (info: ProfileInfo) => void): void;
+    export function installDroppedFile(callback?: VoidCallback): void;
+    export function loadUnpacked(
+        options: LoadUnpackedOptions,
+        callback: (error?: LoadError) => void): void;
+    export function notifyDragInstallInProgress(): void;
+    export function openDevTools(
+        properties: OpenDevToolsProperties, callback?: VoidCallback): void;
+    export function packDirectory(
+        path: string, privateKeyPath: string, flags?: number,
+        callback?: (response: PackDirectoryResponse) => void): void;
+    export function reload(
+        extensionId: string, options?: ReloadOptions,
+        callback?: (error?: LoadError) => void): void;
+    export function removeHostPermission(
+        extensionId: string, host: string, callback: VoidCallback): void;
+    export function repairExtension(
+        extensionId: string, callback?: VoidCallback): void;
+    export function requestFileSource(
+        properties: RequestFileSourceProperties,
+        callback: (response: RequestFileSourceResponse) => void): void;
+    export function setShortcutHandlingSuspended(
+        isSuspended: boolean, callback?: VoidCallback): void;
+    export function showOptions(extensionId: string, callback?: VoidCallback):
+        void;
+    export function showPath(extensionId: string, callback?: VoidCallback):
+        void;
+    export function updateExtensionCommand(
+        update: ExtensionCommandUpdate, callback?: VoidCallback): void;
+    export function updateExtensionConfiguration(
+        update: ExtensionConfigurationUpdate, callback?: VoidCallback): void;
+    export function updateProfileConfiguration(
+        update: ProfileConfigurationUpdate, callback?: VoidCallback): void;
+
+    // This is a workaround for the fact that importing other .d.ts files does
+    // not work. ChromeEvent is also used elsewhere so should be in its own
+    // file.
+    export interface ChromeEvent<ListenerType> {
+      addListener(listener: ListenerType): void;
+      removeListener(listener: ListenerType): void;
+    }
+
+    export const onItemStateChanged: ChromeEvent<(data: EventData) => void>;
+    export const onProfileStateChanged: ChromeEvent<(info: ProfileInfo) => void>;
   }
 }
diff --git a/tools/typescript/definitions/tabs.d.ts b/tools/typescript/definitions/tabs.d.ts
index c87db457..b3c1e7b 100644
--- a/tools/typescript/definitions/tabs.d.ts
+++ b/tools/typescript/definitions/tabs.d.ts
@@ -61,6 +61,6 @@
     }
 
     export function create(createProperties: CreateProperties,
-                           callback?: (p1: Tab) => void): void;
+                           callback?: (Tab) => void): void;
   }
 }
diff --git a/tools/typescript/definitions/windows.d.ts b/tools/typescript/definitions/windows.d.ts
index b3fc288..6fcb395 100644
--- a/tools/typescript/definitions/windows.d.ts
+++ b/tools/typescript/definitions/windows.d.ts
@@ -53,11 +53,11 @@
     export const WINDOW_ID_CURRENT: number;
 
     export function get(windowId: number, getInfo: (GetInfo|null),
-                        callback: (p1: Window) => void): void;
+                        callback: (Window) => void): void;
     export function getCurrent(getInfo: (GetInfo|null),
-                               callback: (p1: Window) => void): void;
+                               callback: (Window) => void): void;
     export function getLastFocused(getInfo: (GetInfo|null),
-                                   callback: (p1: Window) => void): void;
+                                   callback: (Window) => void): void;
     export function getAll(getInfo: (GetInfo|null),
                            callback: (p1: Window[]) => void): void;
     type CreateData = {
@@ -75,7 +75,7 @@
     }
 
     export function create(createData?: CreateData,
-                           callback?: (p1: Window) => void): void;
+                           callback?: (Window) => void): void;
 
     type UpdateInfo = {
       left?: number;
@@ -88,7 +88,7 @@
     }
 
     export function update(windowId: number, updateInfo: UpdateInfo,
-                           callback?: (p1: Window) => void): void;
+                           callback?: (Window) => void): void;
     export function remove(windowId: number, callback?: () => void): void;
   }
 }
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 07d38591e..19a139ad 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -237,11 +237,7 @@
 // for on the current platform. Guaranteed to be in sorted order and guaranteed
 // to have no duplicates.
 //
-// Note that this could have false positives at runtime on Android and iOS:
-// - On Android, some locales aren't shipped (|android_apk_omitted_locales| in
-//   GN), and some locales files are dynamically shipped in app bundles
-//   (|android_bundle_only_locales|). Both of these lists are included in
-//   this variable.
+// Note that this could have false positives at runtime on iOS:
 // - On iOS, some locales aren't shipped (|ios_unsupported_locales|) as they are
 //   not supported by the operating system. These locales are included in this
 //   variable.
diff --git a/ui/base/x/x11_clipboard_helper.cc b/ui/base/x/x11_clipboard_helper.cc
index 1d10ca88..b6d23a1 100644
--- a/ui/base/x/x11_clipboard_helper.cc
+++ b/ui/base/x/x11_clipboard_helper.cc
@@ -225,6 +225,8 @@
     available_types.push_back(kMimeTypePNG);
   if (target_list.ContainsFormat(ClipboardFormatType::GetFilenamesType()))
     available_types.push_back(kMimeTypeURIList);
+  if (target_list.ContainsFormat(ClipboardFormatType::GetWebCustomDataType()))
+    available_types.push_back(kMimeTypeWebCustomData);
 
   return available_types;
 }
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index 12b8aa22..3ef34591 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -146,7 +146,8 @@
   //   implemented.
   z_order_ = z_order_set_ ? z_order_ : plane_z_order;
   if (widget_ != widget || z_order_ != plane_z_order) {
-    buffer_manager_->DestroyBuffer(widget_, buffer_id_);
+    if (widget_ != gfx::kNullAcceleratedWidget)
+      buffer_manager_->DestroyBuffer(widget_, buffer_id_);
     CreateDmabufBasedBuffer();
     widget_ = widget;
     z_order_ = plane_z_order;
diff --git a/ui/resources/PRESUBMIT.py b/ui/resources/PRESUBMIT.py
index 02d0150f..e281f4f 100644
--- a/ui/resources/PRESUBMIT.py
+++ b/ui/resources/PRESUBMIT.py
@@ -10,6 +10,8 @@
 for the rules we're checking against here.
 """
 
+USE_PYTHON3 = True
+
 
 def CheckChangeOnUpload(input_api, output_api):
   return _CommonChecks(input_api, output_api)
diff --git a/ui/resources/resource_check/resource_scale_factors.py b/ui/resources/resource_check/resource_scale_factors.py
index 9b2ee17..3fecdf49f 100644
--- a/ui/resources/resource_check/resource_scale_factors.py
+++ b/ui/resources/resource_check/resource_scale_factors.py
@@ -48,7 +48,7 @@
     def ImageSize(filename):
       with open(filename, 'rb', buffering=0) as f:
         data = f.read(24)
-      if data[:8] != '\x89PNG\r\n\x1A\n' or data[12:16] != 'IHDR':
+      if data[:8] != b'\x89PNG\r\n\x1A\n' or data[12:16] != b'IHDR':
         raise InvalidPNGException
       return struct.unpack('>ii', data[16:24])
 
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index 221366e1..7e91df13 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -157,9 +157,7 @@
   "cr_elements/find_shortcut_behavior.d.ts",
   "cr_elements/policy/cr_tooltip_icon.m.d.ts",
   "js/cr/ui/focus_row_behavior.m.d.ts",
-  "js/cr/ui/store.m.d.ts",
   "js/i18n_behavior.m.d.ts",
-  "js/list_property_update_behavior.m.d.ts",
   "js/promise_resolver.m.d.ts",
   "js/web_ui_listener_behavior.m.d.ts",
 ]
@@ -214,12 +212,11 @@
     "$root_dir/js/cr/ui/focus_grid.m.d.ts",
     "$root_dir/js/cr/ui/focus_outline_manager.m.d.ts",
     "$root_dir/js/cr/ui/focus_row.m.d.ts",
-    "$root_dir/js/cr/ui/keyboard_shortcut_list.m.d.ts",
+    "$root_dir/js/cr/ui/store.m.d.ts",
     "$root_dir/js/cr/ui/store_client.m.d.ts",
     "$root_dir/js/event_tracker.m.d.ts",
     "$root_dir/js/load_time_data.m.d.ts",
     "$root_dir/js/parse_html_subset.m.d.ts",
-    "$root_dir/js/plural_string_proxy.d.ts",
     "$root_dir/js/icon.m.d.ts",
     "$root_dir/js/util.m.d.ts",
   ]
@@ -267,13 +264,12 @@
     "js/cr/ui/focus_grid.m.js",
     "js/cr/ui/focus_outline_manager.m.js",
     "js/cr/ui/focus_row.m.js",
-    "js/cr/ui/keyboard_shortcut_list.m.js",
     "js/cr/ui/store_client.m.js",
+    "js/cr/ui/store.m.js",
     "js/event_tracker.m.js",
     "js/icon.m.js",
     "js/load_time_data.m.js",
     "js/parse_html_subset.m.js",
-    "js/plural_string_proxy.js",
     "js/util.m.js",
   ]
 
diff --git a/ui/webui/resources/js/cr/ui/store.m.d.ts b/ui/webui/resources/js/cr/ui/store.m.d.ts
deleted file mode 100644
index 060242be..0000000
--- a/ui/webui/resources/js/cr/ui/store.m.d.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2021 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.
-
-// Note: This file is mostly autogenerated, but changing Action to a class here
-// so that it can be subclassed for bookmarks without impacting closure
-// compilation for other UIs.
-export class Action {
-  name: string;
-}
-
-export type DeferredAction = (arg0: (arg0: Action | null) => any) => any;
-
-export class StoreObserver<T> {
-  onStateChanged(newState: T): void;
-}
-
-export class Store<T> {
-  constructor(emptyState: T, reducer: (arg0: T, arg1: Action) => T);
-  data: T;
-  reducer_: (arg0: T, arg1: Action) => T;
-  initialized_: boolean;
-  queuedActions_: Array<DeferredAction>;
-  observers_: Array<StoreObserver<any>>;
-  private batchMode_;
-  init(initialState: T): void;
-  isInitialized(): boolean;
-  addObserver(observer: StoreObserver<any>): void;
-  removeObserver(observer: StoreObserver<any>): void;
-  beginBatchUpdate(): void;
-  endBatchUpdate(): void;
-  dispatchAsync(action: DeferredAction): void;
-  dispatch(action: Action | null): void;
-  dispatchInternal_(action: DeferredAction): void;
-  private reduce_;
-  private notifyObservers_;
-}
diff --git a/ui/webui/resources/js/list_property_update_behavior.m.d.ts b/ui/webui/resources/js/list_property_update_behavior.m.d.ts
deleted file mode 100644
index 4af6603..0000000
--- a/ui/webui/resources/js/list_property_update_behavior.m.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2021 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.
-
-export interface ListPropertyUpdateBehaviorInterface {
-  updateList(
-      propertyPath: string,
-      identityGetter: ((arg0: object) => (object | string)),
-      updatedList: object[], identityBasedUpdate?: boolean): boolean;
-}
-
-export {ListPropertyUpdateBehavior};
-
-interface ListPropertyUpdateBehavior extends
-    ListPropertyUpdateBehaviorInterface {}
-
-declare const ListPropertyUpdateBehavior: object;
diff --git a/ui/webui/resources/js/plural_string_proxy.js b/ui/webui/resources/js/plural_string_proxy.js
index 1a314a1..801a414 100644
--- a/ui/webui/resources/js/plural_string_proxy.js
+++ b/ui/webui/resources/js/plural_string_proxy.js
@@ -7,7 +7,7 @@
  */
 
 // clang-format off
-import {sendWithPromise} from './cr.m.js';
+import {addSingletonGetter, sendWithPromise} from './cr.m.js';
 // clang-format on
 
 /** @interface */
@@ -70,17 +70,6 @@
         'getPluralStringTupleWithPeriods', messageName1, itemCount1,
         messageName2, itemCount2);
   }
-
-  /** @return {!PluralStringProxy} */
-  static getInstance() {
-    return instance || (instance = new PluralStringProxyImpl());
-  }
-
-  /** @param {PluralStringProxy} obj */
-  static setInstance(obj) {
-    instance = obj;
-  }
 }
 
-/** @type {?PluralStringProxy} */
-let instance = null;
+addSingletonGetter(PluralStringProxyImpl);
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc
index 8f855b7..8e42fd27 100644
--- a/weblayer/app/content_main_delegate_impl.cc
+++ b/weblayer/app/content_main_delegate_impl.cc
@@ -182,8 +182,6 @@
     ::features::kNotificationTriggers,
     // TODO(crbug.com/1091211): Support PeriodicBackgroundSync on WebLayer.
     ::features::kPeriodicBackgroundSync,
-    // TODO(crbug.com/1131017): Support SurfaceViews on WebLayer.
-    media::kOverlayFullscreenVideo,
     // TODO(crbug.com/1174856): Support Portals.
     blink::features::kPortals,
     // TODO(crbug.com/1174566): Enable by default after experiment.