Revert "Reland "[Insets] Attach InsetObserver directly to ActivityWindowAndroid""

This reverts commit e1180f7d09784ccd680d8d02c64f0236bf208a08.

Reason for revert: Suspected cause for test failure, crbug.com/345372444

Original change's description:
> Reland "[Insets] Attach InsetObserver directly to ActivityWindowAndroid"
>
> This is a reland of commit 384890b3adf44d85a0dbedfc45b542c7bdca95eb
>
> PS1 is the original change.
>
> The main issue with the patchset is it introduced b/344959459. The root
> cause of the bug was holding RootView caused GC to fail for WebView. A
> fix was proposed here and has been folded into this CL.
> https://chromium-review.googlesource.com/c/chromium/src/+/5598361
>
> However, there is still the issue that we probably shouldn't create the
> InsetObserver for WebView in the first place so this CL also addresses
> that by lazily instantiating it only when needed.
>
> I'll land this and then reland the follow-up change after a day so we
> don't need to chain the reverts again.
>
> Original change's description:
> > [Insets] Attach InsetObserver directly to ActivityWindowAndroid
> >
> > Rework the lifecycle of InsetObserver to be tied to
> > ActivityWindowAndroid.
> >
> > Precursor to landing:
> > https://chromium-review.googlesource.com/c/chromium/src/+/5580959
> >
> > Bug: 343224210
> > Change-Id: I15fabd91e614fd690c31ddba8641da9720d073ed
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5589447
> > Reviewed-by: Theresa Sullivan <twellington@chromium.org>
> > Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
> > Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
> > Reviewed-by: Ted Choc <tedchoc@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#1309960}
>
> Include-Ci-Only-Tests: true
> Bug: 343224210
> Change-Id: I439e5d41187b50e75c014232c581597042108946
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5597547
> Reviewed-by: Theresa Sullivan <twellington@chromium.org>
> Reviewed-by: Bo Liu <boliu@chromium.org>
> Reviewed-by: Ted Choc <tedchoc@chromium.org>
> Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
> Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
> Cr-Commit-Position: refs/heads/main@{#1310765}

Bug: 343224210, 345372444
Change-Id: I747b94bd4b537d4c28f3936ccff2c4e6dbea133c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5602672
Auto-Submit: Benoit Lize <lizeb@chromium.org>
Owners-Override: Benoit Lize <lizeb@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Benoit Lize <lizeb@chromium.org>
Reviewed-by: Benoit Lize <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1311116}
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
index caf2f1b..a105a38 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
@@ -95,6 +95,7 @@
 import org.chromium.components.embedder_support.view.ContentView;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -330,7 +331,7 @@
         mJniMocker.mock(ProfileJni.TEST_HOOKS, mProfileJniMock);
         when(mProfileJniMock.fromWebContents(any())).thenReturn(mMockProfile);
 
-        when(mMockWindow.getInsetObserver()).thenReturn(mInsetObserver);
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
         simulateLayoutSizeChange(
                 2.f, 80, 128, /* keyboardShown= */ false, VirtualKeyboardMode.RESIZES_VISUAL);
         Configuration config = new Configuration();
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 f162544a..5a5e53ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2253,7 +2253,7 @@
                 new ObservableSupplierImpl<>(),
                 getIntentRequestTracker(),
                 getControlContainerHeightResource(),
-                getWindowAndroid().getInsetObserver(),
+                mInsetObserverViewSupplier,
                 this::backShouldCloseTab,
                 getTabReparentingControllerSupplier(),
                 // TODO(sinansahin): This currently only checks for incognito extras in the intent.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 48aa8334..af4abc8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -231,6 +231,7 @@
 import org.chromium.printing.PrintingController;
 import org.chromium.printing.PrintingControllerImpl;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.ApplicationViewportInsetSupplier;
@@ -338,6 +339,8 @@
             new ObservableSupplierImpl<>();
     private ObservableSupplierImpl<LayoutManagerImpl> mLayoutManagerSupplier =
             new ObservableSupplierImpl<>();
+    protected final UnownedUserDataSupplier<InsetObserver> mInsetObserverViewSupplier =
+            new InsetObserverSupplier();
     private final ObservableSupplierImpl<ContextualSearchManager> mContextualSearchManagerSupplier =
             new ObservableSupplierImpl<>();
 
@@ -489,6 +492,11 @@
         // insets.
         rootView.setFitsSystemWindows(false);
 
+        // Add an inset observer that stores the insets to access later.
+        // WebContents needs the insets to determine the portion of the screen obscured by
+        // non-content displaying things such as the OSK.
+        mInsetObserverViewSupplier.set(new InsetObserver(rootView));
+
         if (BuildInfo.getInstance().isAutomotive
                 && ChromeFeatureList.sVerticalAutomotiveBackButtonToolbar.isEnabled()) {
             mBaseChromeLayout = new FrameLayout(this);
@@ -566,6 +574,7 @@
         mTabModelSelectorSupplier.attach(getWindowAndroid().getUnownedUserDataHost());
         mTabCreatorManagerSupplier.attach(getWindowAndroid().getUnownedUserDataHost());
         mManualFillingComponentSupplier.attach(getWindowAndroid().getUnownedUserDataHost());
+        mInsetObserverViewSupplier.attach(getWindowAndroid().getUnownedUserDataHost());
         mBrowserControlsManagerSupplier.attach(getWindowAndroid().getUnownedUserDataHost());
         // BrowserControlsManager is ready immediately.
         mBrowserControlsManagerSupplier.set(
@@ -692,7 +701,7 @@
             mBottomContainer = (BottomContainer) findViewById(R.id.bottom_container);
 
             mSnackbarManager = new SnackbarManager(this, mBottomContainer, getWindowAndroid());
-            getWindowAndroid().getInsetObserver().addObserver(mSnackbarManager);
+            mInsetObserverViewSupplier.get().addObserver(mSnackbarManager);
             SnackbarManagerProvider.attach(getWindowAndroid(), mSnackbarManager);
 
             // Make the activity listen to policy change events
@@ -1703,17 +1712,9 @@
             mBottomContainer = null;
         }
 
-        WindowAndroid windowAndroid = getWindowAndroid();
-        if (windowAndroid != null) {
-            if (mDisplayAndroidObserver != null) {
-                windowAndroid.getDisplay().removeObserver(mDisplayAndroidObserver);
-                mDisplayAndroidObserver = null;
-            }
-
-            InsetObserver insetObserver = windowAndroid.getInsetObserver();
-            if (insetObserver != null) {
-                insetObserver.removeObserver(mSnackbarManager);
-            }
+        if (mDisplayAndroidObserver != null) {
+            getWindowAndroid().getDisplay().removeObserver(mDisplayAndroidObserver);
+            mDisplayAndroidObserver = null;
         }
 
         if (mTextBubbleBackPressHandler != null) {
@@ -1736,6 +1737,10 @@
             mStylusWritingCoordinator = null;
         }
 
+        if (mInsetObserverViewSupplier.get() != null) {
+            mInsetObserverViewSupplier.get().removeObserver(mSnackbarManager);
+        }
+
         // Destroy spare tab on activity destruction.
         WarmupManager warmupManager = WarmupManager.getInstance();
         warmupManager.destroySpareTab();
@@ -2167,7 +2172,7 @@
         ApplicationViewportInsetSupplier insetSupplier =
                 getWindowAndroid().getApplicationBottomInsetSupplier();
         insetSupplier.setKeyboardInsetSupplier(
-                getWindowAndroid().getInsetObserver().getSupplierForKeyboardInset());
+                mInsetObserverViewSupplier.get().getSupplierForKeyboardInset());
         insetSupplier.setKeyboardAccessoryInsetSupplier(
                 mManualFillingComponentSupplier.get().getBottomInsetSupplier());
         compositorViewHolder.setApplicationViewportInsetSupplier(insetSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java
index 6e1c3cb..fa8db11 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java
@@ -23,6 +23,7 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -91,7 +92,7 @@
 
         @Override
         public InsetObserver getInsetObserverView() {
-            return mTab.getWindowAndroid().getInsetObserver();
+            return InsetObserverSupplier.getValueOrNullFrom(mTab.getWindowAndroid());
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index a7265f3c..f74ae0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -34,6 +34,7 @@
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneShotCallback;
 import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.base.supplier.UnownedUserDataSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
@@ -78,6 +79,8 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ContentUrlConstants;
+import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.WindowDelegate;
@@ -233,6 +236,8 @@
     private SnackbarManager mSnackbarManager;
     private Tab mTab;
     private final ObservableSupplierImpl<Profile> mProfileSupplier = new ObservableSupplierImpl<>();
+    protected final UnownedUserDataSupplier<InsetObserver> mInsetObserverViewSupplier =
+            new InsetObserverSupplier();
 
     // SearchBoxDataProvider and LocationBarEmbedderUiOverrides are passed to several child
     // components upon construction. Ensure we don't accidentally introduce disconnection by
@@ -282,6 +287,11 @@
         // Setting fitsSystemWindows to false ensures that the root view doesn't consume the
         // insets.
         rootView.setFitsSystemWindows(false);
+        // Add an inset observer that stores the insets to access later.
+        // WebContents needs the insets to determine the portion of the screen obscured by
+        // non-content displaying things such as the OSK.
+        mInsetObserverViewSupplier.attach(getWindowAndroid().getUnownedUserDataHost());
+        mInsetObserverViewSupplier.set(new InsetObserver(rootView));
 
         var contentView = createContentView();
         setContentView(contentView);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index 964fea7..fcc379f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -185,7 +185,7 @@
     private CommerceSubscriptionsService mCommerceSubscriptionsService;
     private UndoGroupSnackbarController mUndoGroupSnackbarController;
     private final int mControlContainerHeightResource;
-    private final InsetObserver mInsetObserver;
+    private final Supplier<InsetObserver> mInsetObserverViewSupplier;
     private final Function<Tab, Boolean> mBackButtonShouldCloseTabFn;
     private LayoutStateProvider.LayoutStateObserver mGestureNavLayoutObserver;
     private final ObservableSupplierImpl<EphemeralTabCoordinator> mEphemeralTabCoordinatorSupplier;
@@ -275,7 +275,7 @@
      * @param ephemeralTabCoordinatorSupplier Supplies the {@link EphemeralTabCoordinator}.
      * @param intentRequestTracker Tracks intent requests.
      * @param controlContainerHeightResource The resource for the control container.
-     * @param insetObserver The {@link InsetObserver}.
+     * @param insetObserverViewSupplier Supplier for the {@link InsetObserver}.
      * @param backButtonShouldCloseTabFn Function which supplies whether or not the back button
      *     should close the tab.
      * @param tabReparentingControllerSupplier Supplier for the {@link TabReparentingController}.
@@ -330,7 +330,7 @@
                     ObservableSupplierImpl<EphemeralTabCoordinator> ephemeralTabCoordinatorSupplier,
             @NonNull IntentRequestTracker intentRequestTracker,
             int controlContainerHeightResource,
-            @NonNull InsetObserver insetObserver,
+            @NonNull Supplier<InsetObserver> insetObserverViewSupplier,
             @NonNull Function<Tab, Boolean> backButtonShouldCloseTabFn,
             OneshotSupplier<TabReparentingController> tabReparentingControllerSupplier,
             boolean initializeUiWithIncognitoColors,
@@ -385,7 +385,7 @@
                 overviewColorSupplier,
                 baseChromeLayout);
         mControlContainerHeightResource = controlContainerHeightResource;
-        mInsetObserver = insetObserver;
+        mInsetObserverViewSupplier = insetObserverViewSupplier;
         mBackButtonShouldCloseTabFn = backButtonShouldCloseTabFn;
         mEphemeralTabCoordinatorSupplier = ephemeralTabCoordinatorSupplier;
         mCanAnimateBrowserControls =
@@ -533,7 +533,7 @@
                         mContextualSearchManagerSupplier,
                         getBottomSheetController(),
                         mToolbarManager.getLocationBar().getOmniboxSuggestionsVisualState(),
-                        mInsetObserver);
+                        mInsetObserverViewSupplier.get());
     }
 
     @Override
@@ -603,7 +603,7 @@
                         mCallbackController.makeCancelable(
                                 () -> mLayoutManager.getActiveLayout().requestUpdate()),
                         mActivityTabProvider,
-                        mInsetObserver,
+                        mInsetObserverViewSupplier.get(),
                         mStartSurfaceSupplier,
                         new BackActionDelegate() {
                             @Override
@@ -1232,7 +1232,7 @@
                         mActivity,
                         mActivity.getWindow().getDecorView().getRootView(),
                         mBrowserControlsManager.getBrowserVisibilityDelegate(),
-                        mInsetObserver,
+                        mInsetObserverViewSupplier.get(),
                         mActivityLifecycleDispatcher,
                         savedInstanceState);
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java
index 56be3e9..4417a3b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java
@@ -39,6 +39,7 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.lang.ref.WeakReference;
@@ -81,8 +82,8 @@
         when(mTab.getUserDataHost()).thenReturn(mTabDataHost);
         when(mWebContents.isFullscreenForCurrentTab()).thenReturn(true);
         when(mWindowAndroid.getActivity()).thenReturn(mActivityRef);
-        when(mWindowAndroid.getInsetObserver()).thenReturn(mInsetObserver);
 
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
         ActivityDisplayCutoutModeSupplier.setInstanceForTesting(0);
 
         mDisplayCutoutTabHelper = spy(new DisplayCutoutTabHelper(mTab));
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
index 364f437f..cceb631a 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -60,6 +60,7 @@
 import org.chromium.content_public.browser.GlobalRenderFrameHostId;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.url.GURL;
@@ -628,7 +629,8 @@
                         }
                     };
 
-            InsetObserver insetObserver = mActivityWindowAndroid.getInsetObserver();
+            InsetObserver insetObserver =
+                    InsetObserverSupplier.getValueOrNullFrom(mActivityWindowAndroid);
             if (insetObserver != null) {
                 insetObserver.addObserver(this);
             }
@@ -967,7 +969,8 @@
         resetCurrentPlayback();
         mStateToRestoreOnBringingToForeground = null;
         ReadAloudFeatures.shutdown();
-        InsetObserver insetObserver = mActivityWindowAndroid.getInsetObserver();
+        InsetObserver insetObserver =
+                InsetObserverSupplier.getValueOrNullFrom(mActivityWindowAndroid);
         if (insetObserver != null) {
             insetObserver.removeObserver(this);
         }
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java
index 112f1e0..f706349 100644
--- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java
+++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java
@@ -31,6 +31,7 @@
 import org.chromium.content_public.browser.WebContentsObserver.ViewportFitType;
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.InsetObserver.WindowInsetsConsumer;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -120,7 +121,7 @@
                 TotallyEdgeToEdge.isEnabled()
                         ? new TotallyEdgeToEdge(browserControlsStateProvider, this::maybeDrawToEdge)
                         : null;
-        mInsetObserver = mWindowAndroid.getInsetObserver();
+        mInsetObserver = InsetObserverSupplier.getValueOrNullFrom(mWindowAndroid);
         mBrowserControlsStateProvider = browserControlsStateProvider;
         mBrowserControlsStateProvider.addObserver(this);
     }
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerTest.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerTest.java
index 10a1de8..9133b3e9 100644
--- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerTest.java
+++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerTest.java
@@ -64,6 +64,7 @@
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.InsetObserver.WindowInsetsConsumer;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -125,7 +126,7 @@
         ChromeFeatureList.sDrawWebEdgeToEdge.setForTesting(false);
 
         MockitoAnnotations.openMocks(this);
-        when(mWindowAndroid.getInsetObserver()).thenReturn(mInsetObserver);
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
 
         mActivity = Robolectric.buildActivity(AppCompatActivity.class).setup().get();
         mTabProvider = new ObservableSupplierImpl<>();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallback.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallback.java
index 895aace..6ed6c0a 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallback.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallback.java
@@ -15,6 +15,7 @@
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.InsetObserver.WindowInsetsAnimationListener;
 import org.chromium.ui.InsetObserver.WindowInsetsConsumer;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.util.List;
@@ -50,7 +51,7 @@
      * window insets and listening for IME animation updates.
      */
     public void attach(WindowAndroid windowAndroid) {
-        InsetObserver insetObserver = windowAndroid.getInsetObserver();
+        InsetObserver insetObserver = InsetObserverSupplier.getValueOrNullFrom(windowAndroid);
         assert insetObserver != null
                 : "DeferredIMEWindowInsetApplicationCallback can only be used in activities with an"
                         + " InsetObserverView";
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallbackTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallbackTest.java
index e97ace19..e8b30164 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallbackTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/DeferredIMEWindowInsetApplicationCallbackTest.java
@@ -8,7 +8,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.view.View;
 
@@ -26,6 +25,7 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
 /** Unit tests for {@link DeferredIMEWindowInsetApplicationCallback}. */
@@ -44,11 +44,11 @@
     @Mock private Runnable mUpdateRunnable;
     @Mock private WindowAndroid mWindowAndroid;
     @Mock private View mView;
-    @Mock private InsetObserver mInsetObserver;
+    @Mock InsetObserver mInsetObserver;
 
     @Before
     public void setUp() {
-        when(mWindowAndroid.getInsetObserver()).thenReturn(mInsetObserver);
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
         mAnimation = new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.ime(), null, 160);
         mAnimation2 = new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.ime(), null, 160);
         mCallback = new DeferredIMEWindowInsetApplicationCallback(mUpdateRunnable);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsDropdownEmbedderImplTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsDropdownEmbedderImplTest.java
index 04bc53f7..486be240 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsDropdownEmbedderImplTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsDropdownEmbedderImplTest.java
@@ -33,6 +33,7 @@
 import org.chromium.chrome.browser.omnibox.styles.OmniboxResourceProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsDropdownEmbedder.OmniboxAlignment;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
@@ -78,7 +79,7 @@
     @Before
     public void setUp() {
         mContextWeakRef = new WeakReference<>(ContextUtils.getApplicationContext());
-        doReturn(mInsetObserver).when(mWindowAndroid).getInsetObserver();
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
         doReturn(mContextWeakRef).when(mWindowAndroid).getContext();
         doReturn(mContextWeakRef.get()).when(mAnchorView).getContext();
         doReturn(mViewTreeObserver).when(mAnchorView).getViewTreeObserver();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
index c7ae299..26abcc3 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -90,6 +90,7 @@
 import org.chromium.components.omnibox.suggestions.OmniboxSuggestionUiType;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
@@ -195,7 +196,7 @@
         mListModel.set(SuggestionListProperties.SUGGESTION_MODELS, mSuggestionModels);
 
         mTabWindowManagerSupplier = new ObservableSupplierImpl<>();
-        doReturn(mInsetObserver).when(mWindowAndroid).getInsetObserver();
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
 
         mMediator =
                 new AutocompleteMediator(
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriver.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriver.java
index 8a2d511..2d9e5c1 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriver.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriver.java
@@ -11,6 +11,7 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.InsetObserver.WindowInsetsAnimationListener;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -56,7 +57,7 @@
 
     void onOmniboxSessionStateChange(boolean active) {
         if (active) {
-            InsetObserver insetObserver = mWindowAndroid.getInsetObserver();
+            InsetObserver insetObserver = InsetObserverSupplier.getValueOrNullFrom(mWindowAndroid);
             insetObserver.addWindowInsetsAnimationListener(this);
         } else {
             removeInsetListener();
@@ -64,7 +65,7 @@
     }
 
     private void removeInsetListener() {
-        InsetObserver insetObserver = mWindowAndroid.getInsetObserver();
+        InsetObserver insetObserver = InsetObserverSupplier.getValueOrNullFrom(mWindowAndroid);
         insetObserver.removeWindowInsetsAnimationListener(this);
     }
 
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriverTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriverTest.java
index 2d011e6..2a7169d 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriverTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsListAnimationDriverTest.java
@@ -7,7 +7,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import androidx.core.view.WindowInsetsAnimationCompat;
 import androidx.core.view.WindowInsetsCompat;
@@ -23,6 +22,7 @@
 import org.chromium.base.MathUtils;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.ui.InsetObserver;
+import org.chromium.ui.InsetObserverSupplier;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -47,7 +47,7 @@
     @Before
     public void setUp() {
         mTranslation = 0.0f;
-        when(mWindowAndroid.getInsetObserver()).thenReturn(mInsetObserver);
+        InsetObserverSupplier.setInstanceForTesting(mInsetObserver);
         mImeAnimation = new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.ime(), null, 160);
         mNonImeAnimation =
                 new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.statusBars(), null, 160);
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index af718c1..e287512 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -282,6 +282,7 @@
     "java/src/org/chromium/ui/ElidedUrlTextView.java",
     "java/src/org/chromium/ui/HorizontalListDividerDrawable.java",
     "java/src/org/chromium/ui/InsetObserver.java",
+    "java/src/org/chromium/ui/InsetObserverSupplier.java",
     "java/src/org/chromium/ui/InsetsRectProvider.java",
     "java/src/org/chromium/ui/LayoutInflaterUtils.java",
     "java/src/org/chromium/ui/OverscrollRefreshHandler.java",
diff --git a/ui/android/java/src/org/chromium/ui/InsetObserver.java b/ui/android/java/src/org/chromium/ui/InsetObserver.java
index e1bad0e8..baed1ca 100644
--- a/ui/android/java/src/org/chromium/ui/InsetObserver.java
+++ b/ui/android/java/src/org/chromium/ui/InsetObserver.java
@@ -21,7 +21,6 @@
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
-import org.chromium.ui.base.ImmutableWeakReference;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -40,7 +39,7 @@
     private final ObserverList<WindowInsetsAnimationListener> mWindowInsetsAnimationListeners =
             new ObserverList<>();
     private final List<WindowInsetsConsumer> mInsetsConsumers = new ArrayList<>();
-    private final ImmutableWeakReference<View> mRootViewReference;
+    private final View mRootView;
     // Insets to be added to the current safe area.
     private int mBottomInsetsForEdgeToEdge;
     private final Rect mDisplayCutoutRect;
@@ -111,10 +110,10 @@
     /**
      * Creates an instance of {@link InsetObserver}.
      *
-     * @param rootViewWeakRef A weak reference to the root view of the app.
+     * @param rootView The root view of the app.
      */
-    public InsetObserver(ImmutableWeakReference<View> rootViewWeakRef) {
-        mRootViewReference = rootViewWeakRef;
+    public InsetObserver(View rootView) {
+        mRootView = rootView;
         mWindowInsets = new Rect();
         mCurrentSafeArea = new Rect();
         mDisplayCutoutRect = new Rect();
@@ -168,13 +167,10 @@
                     }
                 };
 
-        View rootView = getRootView();
-        if (rootView == null) return;
-
         // Populate the root window insets if available.
-        if (rootView.getRootWindowInsets() != null) {
+        if (mRootView.getRootWindowInsets() != null) {
             mLastSeenRawWindowInset =
-                    WindowInsetsCompat.toWindowInsetsCompat(rootView.getRootWindowInsets());
+                    WindowInsetsCompat.toWindowInsetsCompat(mRootView.getRootWindowInsets());
         } else if (sInitialRawWindowInsetsForTesting != null) {
             mLastSeenRawWindowInset = sInitialRawWindowInsetsForTesting;
         }
@@ -283,11 +279,7 @@
     }
 
     private void updateKeyboardInset() {
-        View rootView = mRootViewReference.get();
-        if (rootView == null) return;
-
-        int keyboardInset = KeyboardUtils.calculateKeyboardHeightFromWindowInsets(rootView);
-
+        int keyboardInset = KeyboardUtils.calculateKeyboardHeightFromWindowInsets(mRootView);
         if (mKeyboardInset == keyboardInset) {
             return;
         }
@@ -300,11 +292,8 @@
     }
 
     private WindowInsetsCompat forwardToInsetConsumers(WindowInsetsCompat insets) {
-        View rootView = mRootViewReference.get();
-        if (rootView == null) return insets;
-
         for (WindowInsetsConsumer consumer : mInsetsConsumers) {
-            insets = consumer.onApplyWindowInsets(rootView, insets);
+            insets = consumer.onApplyWindowInsets(mRootView, insets);
         }
         return insets;
     }
@@ -363,8 +352,4 @@
         sInitialRawWindowInsetsForTesting = windowInsets;
         ResettersForTesting.register(() -> sInitialRawWindowInsetsForTesting = null);
     }
-
-    private View getRootView() {
-        return mRootViewReference.get();
-    }
 }
diff --git a/ui/android/java/src/org/chromium/ui/InsetObserverSupplier.java b/ui/android/java/src/org/chromium/ui/InsetObserverSupplier.java
new file mode 100644
index 0000000..c928b19
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/InsetObserverSupplier.java
@@ -0,0 +1,50 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.UnownedUserDataKey;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.UnownedUserDataSupplier;
+import org.chromium.ui.base.WindowAndroid;
+
+/**
+ * A {@link UnownedUserDataSupplier} which manages the supplier and UnownedUserData for a {@link
+ * InsetObserver}.
+ */
+public class InsetObserverSupplier extends UnownedUserDataSupplier<InsetObserver> {
+    private static final UnownedUserDataKey<InsetObserverSupplier> KEY =
+            new UnownedUserDataKey<>(InsetObserverSupplier.class);
+    private static ObservableSupplierImpl<InsetObserver> sInstanceForTesting;
+
+    /** Returns {@link InsetObserver} supplier associated with the given {@link WindowAndroid}. */
+    public static ObservableSupplier<InsetObserver> from(@Nullable WindowAndroid windowAndroid) {
+        if (windowAndroid == null) return null;
+        if (sInstanceForTesting != null) return sInstanceForTesting;
+        return KEY.retrieveDataFromHost(windowAndroid.getUnownedUserDataHost());
+    }
+
+    /** Retrieves a {@link InsetObserver} from {@link WindowAndroid}. */
+    public static @Nullable InsetObserver getValueOrNullFrom(
+            @Nullable WindowAndroid windowAndroid) {
+        ObservableSupplier<InsetObserver> supplier = from(windowAndroid);
+        return supplier == null ? null : supplier.get();
+    }
+
+    /** Sets an instance for testing. */
+    public static void setInstanceForTesting(InsetObserver insetObserver) {
+        if (sInstanceForTesting == null) {
+            sInstanceForTesting = new ObservableSupplierImpl<>();
+        }
+        sInstanceForTesting.set(insetObserver);
+    }
+
+    /** Constructor. */
+    public InsetObserverSupplier() {
+        super(KEY);
+    }
+}
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index e9770ab..6226216 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -45,7 +45,6 @@
 import org.chromium.base.UnownedUserDataHost;
 import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.compat.ApiHelperForOMR1;
-import org.chromium.ui.InsetObserver;
 import org.chromium.ui.KeyboardVisibilityDelegate;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.DisplayAndroid.DisplayAndroidObserver;
@@ -77,8 +76,6 @@
     private KeyboardVisibilityDelegate mKeyboardVisibilityDelegate =
             KeyboardVisibilityDelegate.getInstance();
 
-    private InsetObserver mInsetObserver;
-
     // Native pointer to the c++ WindowAndroid object.
     private long mNativeWindowAndroid;
     private final DisplayAndroid mDisplayAndroid;
@@ -702,41 +699,25 @@
         mAnimationPlaceholderView = view;
     }
 
-    protected void setKeyboardDelegate(KeyboardVisibilityDelegate keyboardDelegate) {
-        mKeyboardVisibilityDelegate = keyboardDelegate;
-        // TODO(crbug.com/343936788): Remove - callers should use the window to get the delegate.
-        KeyboardVisibilityDelegate.setInstance(keyboardDelegate);
-    }
-
     /**
      * The returned {@link KeyboardVisibilityDelegate} can read and influence the soft keyboard.
-     *
      * @return a {@link KeyboardVisibilityDelegate} specific for this window.
      */
     public KeyboardVisibilityDelegate getKeyboardDelegate() {
         return mKeyboardVisibilityDelegate;
     }
 
-    /** Returns the {@link InsetObserver} for the root view of the activity or null. */
-    public InsetObserver getInsetObserver() {
-        if (mInsetObserver == null) {
-            Window window = getWindow();
-            if (window == null) return null;
-
-            mInsetObserver =
-                    new InsetObserver(
-                            new ImmutableWeakReference<>(window.getDecorView().getRootView()));
-        }
-        return mInsetObserver;
-    }
-
-    /**
-     * @return A mechanism for updating and observing the bottom inset of the browser window.
-     */
+    /** @return A mechanism for updating and observing the bottom inset of the browser window. */
     public ApplicationViewportInsetSupplier getApplicationBottomInsetSupplier() {
         return mApplicationBottomInsetSupplier;
     }
 
+    public void setKeyboardDelegate(KeyboardVisibilityDelegate keyboardDelegate) {
+        mKeyboardVisibilityDelegate = keyboardDelegate;
+        // TODO(crbug.com/343936788): Remove - callers should use the window to get the delegate.
+        KeyboardVisibilityDelegate.setInstance(keyboardDelegate);
+    }
+
     /** Adds a listener that will be notified whenever a ContextMenu is closed. */
     public void addContextMenuCloseListener(OnCloseContextMenuListener listener) {
         mContextMenuCloseListeners.addObserver(listener);
diff --git a/ui/android/junit/src/org/chromium/ui/InsetObserverTest.java b/ui/android/junit/src/org/chromium/ui/InsetObserverTest.java
index f94d904..052f5d843 100644
--- a/ui/android/junit/src/org/chromium/ui/InsetObserverTest.java
+++ b/ui/android/junit/src/org/chromium/ui/InsetObserverTest.java
@@ -16,7 +16,6 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
-import android.view.View;
 import android.view.WindowInsets;
 import android.widget.LinearLayout;
 
@@ -38,7 +37,6 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.ui.InsetObserver.WindowInsetsAnimationListener;
 import org.chromium.ui.InsetObserver.WindowInsetsConsumer;
-import org.chromium.ui.base.ImmutableWeakReference;
 
 import java.util.Collections;
 
@@ -100,7 +98,7 @@
                 .when(mModifiedInsets)
                 .getInsets(WindowInsetsCompat.Type.systemBars());
 
-        mInsetObserver = new InsetObserver(new ImmutableWeakReference<View>(mContentView));
+        mInsetObserver = new InsetObserver(mContentView);
         mInsetObserver.addObserver(mObserver);
     }
 
@@ -267,7 +265,7 @@
     @Config(sdk = VERSION_CODES.R)
     public void initializeWithLastSeenRawWindowInsets() {
         doReturn(mNonCompatInsets).when(mContentView).getRootWindowInsets();
-        mInsetObserver = new InsetObserver(new ImmutableWeakReference<View>(mContentView));
+        mInsetObserver = new InsetObserver(mContentView);
         assertEquals(
                 "WindowInsets is different.",
                 WindowInsetsCompat.toWindowInsetsCompat(mNonCompatInsets),