CVE-2026-0906
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java |
modified |
Files Changed
chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.javachrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java
Patch
From d9cb337ff4a744969259fa8cac73512f4f5fe2a4 Mon Sep 17 00:00:00 2001 From: Patrick Noland <[email protected]> Date: Thu, 11 Dec 2025 15:20:05 -0800 Subject: [PATCH] Force relayout for tab-driven constraint changes This logic currently only runs for browserdelegate-driven constraint changes, which misses e.g. form-field focus driven SHOWN. Bug: 467448811 Change-Id: I5662353216c8faea84a98e2f3edfa584cd6adf2c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7253201 Reviewed-by: Wenyu Fu <[email protected]> Commit-Queue: Patrick Noland <[email protected]> Cr-Commit-Position: refs/heads/main@{#1557729} --- diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java index 1f6a93c..9a78efa6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java @@ -222,47 +222,7 @@ mBrowserVisibilityDelegate = new BrowserStateBrowserControlsVisibilityDelegate( mHtmlApiHandler.getPersistentFullscreenModeSupplier()); - mBrowserVisibilityDelegate.addObserver( - (constraints) -> { - if (constraints == BrowserControlsState.SHOWN) { - // When compositor can drive the animation to show controls, do not call - // setPositionsForTabToNonFullscreen to avoid control offset being forced - // set to 0 before the render-driven animation kicks in. - boolean allowRenderDrivenShowConstraint = - ChromeFeatureList.sBrowserControlsRenderDrivenShowConstraint - .isEnabled(); - boolean renderDrivenShowConstraint = - allowRenderDrivenShowConstraint - && canAnimateNativeBrowserControls(); - if (!renderDrivenShowConstraint) { - setPositionsForTabToNonFullscreen(); - } - - // TODO(https://crbug.com/449011189): Maybe cleanup - if (allowRenderDrivenShowConstraint) { - RecordHistogram.recordBooleanHistogram( - "Android.BrowserControls.RenderDrivenShowConstraint", - renderDrivenShowConstraint); - } - - // If controls become locked, it's possible we've previously delayed - // actually setting visibility until a touch event is over. In this case, we - // need to trigger an update again now, which should go through due to - // constraints. - scheduleVisibilityUpdate(); - } - - // From https://crbug.com/452885338, https://crbug.com/461532432: When changing - // controls visibility when exiting fullscreen, the visibility change might not - // honor a redraw. We do this through forcing a relayout to avoid the toolbar - // remains hidden. - if ((constraints == BrowserControlsState.SHOWN - || constraints == BrowserControlsState.BOTH) - && getAndroidControlsVisibility() != View.VISIBLE) { - mForceRelayoutOnVisibilityChange = true; - scheduleVisibilityUpdate(); - } - }); + mBrowserVisibilityDelegate.addObserver(this::onConstraintsChanged); } /** @@ -354,9 +314,10 @@ new OffsetTagConstraints( 0, 0, -(mTopControlsHeight + hairlineHeight), 0); + onConstraintsChanged(constraints); // Notify observers of changes before passing tags to native so observers // can set their relevant fields in offsetTagsInfo. - notifyConstraintsChanged(oldOffsetTagsInfo, offsetTagsInfo, constraints); + notifyOffsetTagsChanged(oldOffsetTagsInfo, offsetTagsInfo, constraints); offsetTagsInfo .getConstraints() @@ -850,7 +811,9 @@ return; } final int desiredVisibility = shouldShowAndroidControls() ? View.VISIBLE : View.INVISIBLE; - if (mControlContainer.getView().getVisibility() == desiredVisibility) return; + if (mControlContainer.getView().getVisibility() == desiredVisibility) { + return; + } mControlContainer.getView().removeCallbacks(mUpdateVisibilityRunnable); mControlContainer.getView().postOnAnimation(mUpdateVisibilityRunnable); } @@ -1022,7 +985,45 @@ } } - private void notifyConstraintsChanged( + private void onConstraintsChanged(@BrowserControlsState int constraints) { + if (constraints == BrowserControlsState.SHOWN) { + // When compositor can drive the animation to show controls, do not call + // setPositionsForTabToNonFullscreen to avoid control offset being forced + // set to 0 before the render-driven animation kicks in. + boolean allowRenderDrivenShowConstraint = + ChromeFeatureList.sBrowserControlsRenderDrivenShowConstraint.isEnabled(); + boolean renderDrivenShowConstraint = + allowRenderDrivenShowConstraint && canAnimateNativeBrowserControls(); + if (!renderDrivenShowConstraint) { + setPositionsForTabToNonFullscreen(); + } + + // TODO(https://crbug.com/449011189): Maybe cleanup + if (allowRenderDrivenShowConstraint) { + RecordHistogram.recordBooleanHistogram( + "Android.BrowserControls.RenderDrivenShowConstraint", + renderDrivenShowConstraint); + } + + // If controls become locked, it's possible we've previously delayed + // actually setting visibility until a touch event is over. In this case, we + // need to trigger an update again now, which should go through due to + // constraints. + scheduleVisibilityUpdate(); + } + + // From https://crbug.com/452885338, https://crbug.com/461532432: When changing + // controls visibility when exiting fullscreen, the visibility change might not + // honor a redraw. We do this through forcing a relayout to avoid the toolbar + // remains hidden. + if ((constraints == BrowserControlsState.SHOWN || constraints == BrowserControlsState.BOTH) + && getAndroidControlsVisibility() != View.VISIBLE) { + mForceRelayoutOnVisibilityChange = true; + scheduleVisibilityUpdate(); + } + } + + private void notifyOffsetTagsChanged( BrowserControlsOffsetTagsInfo oldOffsetTagsInfo, BrowserControlsOffsetTagsInfo offsetTagsInfo, @BrowserControlsState int constraints) { diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java index 60399a7..e1d8392 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java @@ -54,6 +54,7 @@ import org.chromium.cc.input.BrowserControlsState; import org.chromium.chrome.R; import org.chromium.chrome.browser.ActivityTabProvider; +import org.chromium.chrome.browser.browser_controls.BrowserControlsOffsetTagsInfo; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider.ControlsPosition; import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate; @@ -784,6 +785,28 @@ anyBoolean()); } + @Test + public void testConstraintChangeFromTab() { + remakeWithoutSpy(); + notifyAddTab(mTab); + mActivityTabProvider.setForTesting(mTab); + // Put the control container in a hidden state and bottom-positioned. + mBrowserControlsManager.setControlsPosition( + ControlsPosition.BOTTOM, 0, 0, 0, TOOLBAR_HEIGHT, 10, TOOLBAR_HEIGHT); + ShadowLooper.idleMainLooper(); + Mockito.clearInvocations(mContainerView); + // Locking the controls via the TabControlsObserver should check for forced relayout. + mBrowserControlsManager + .getTabControlsObserverForTesting() + .onOffsetTagsInfoChanged( + mTab, + new BrowserControlsOffsetTagsInfo(), + new BrowserControlsOffsetTagsInfo(), + BrowserControlsState.SHOWN); + ShadowLooper.idleMainLooper(); + verify(mContainerView).requestLayout(); + } + private void verifyUpdateOffsetTagDefinitions( OffsetTagConstraints top, OffsetTagConstraints content, OffsetTagConstraints bottom) { BrowserControlsOffsetTagConstraints expectedConstraints =
Original Bug Report
Mini bar not rendered when omnibox is hidden (similar to issue 461532432)
Steps to reproduce the problem
- Open the testcase.
- Scroll down to the middle of the page until the omnibox disappears (normal fullscreen scroll behavior).
- Tap inside the <textarea>.
Problem Description
This issue appears very similar to Chromium issue 461532432.
In Chrome Canary on Android, when the omnibox auto-hides during scroll, tapping inside a <textarea> causes the keyboard’s accessory bar (the mini bar above the virtual keyboard) to not render at all. The space where the accessory bar normally appears is still allocated, but it is completely empty (no icons, no background, just blank UI).
This empty UI zone appears exactly where a user expects browser controls. A website can use CSS to place a fake omnibox just below it, enabling UI spoofing.
Summary
Mini bar not rendered when omnibox is hidden (similar to issue 461532432)
Additional Data
Category: Security
Chrome Channel: Canary
Regression: N/A \