Chrome · Browser UI
CVE-2025-1917
Logic Error in Browser UI
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java |
modified |
Files Changed
chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.javachrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.javachrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
Patch
From 9e3dedd19349d812d7dba808f07ebee91302623e Mon Sep 17 00:00:00 2001
From: Jinsuk Kim <jinsukkim@chromium.org>
Date: Tue, 07 Jan 2025 09:44:22 -0800
Subject: [PATCH] [Android] Fix floating action bar/top control overlapping bug
In order to avoid the floating bar and the top control overlapping
with each other, this CL ensures that the action bar will be drawn
above the selected text only if there is enough space.
Bug: 329476341
Change-Id: I7095863a845db2aa38a4d9d93efde2f2075e82a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6148920
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: Theresa Sullivan <twellington@chromium.org>
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1403053}
---
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java
index b658d84..d01c14ba0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java
@@ -23,6 +23,7 @@
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
+import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
import org.chromium.chrome.browser.firstrun.FirstRunStatus;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.readaloud.ReadAloudController;
@@ -60,12 +61,15 @@
* @param searchCallback Callback to run when search action is selected in the action mode.
* @param shareDelegateSupplier The {@link Supplier} of the {@link ShareDelegate} that will be
* notified when a share action is performed.
+ * @param controlsState Provides browser controls visibility state.
+ * @param readAloudControllerSupplier Supplies {@link ReadAloudController}.
*/
public ChromeActionModeHandler(
ActivityTabProvider activityTabProvider,
Callback<String> searchCallback,
boolean showWebSearch,
Supplier<ShareDelegate> shareDelegateSupplier,
+ BrowserControlsStateProvider controlsState,
Supplier<ReadAloudController> readAloudControllerSupplier) {
mInitWebContentsObserver =
(webContents) -> {
@@ -78,6 +82,7 @@
searchCallback,
showWebSearch,
shareDelegateSupplier,
+ controlsState,
readAloudControllerSupplier));
spc.setDropdownMenuDelegate(new ChromeSelectionDropdownMenuDelegate());
};
@@ -124,6 +129,7 @@
private final boolean mShowWebSearch;
private final Supplier<ShareDelegate> mShareDelegateSupplier;
private final Supplier<ReadAloudController> mReadAloudControllerSupplier;
+ private final BrowserControlsStateProvider mControlsState;
// Used for recording UMA histograms.
private long mContextMenuStartTime;
@@ -134,12 +140,14 @@
Callback<String> searchCallback,
boolean showWebSearch,
Supplier<ShareDelegate> shareDelegateSupplier,
+ BrowserControlsStateProvider controlsState,
Supplier<ReadAloudController> readAloudControllerSupplier) {
mTab = tab;
mHelper = getActionModeCallbackHelper(webContents);
mShowWebSearch = showWebSearch;
mSearchCallback = searchCallback;
mShareDelegateSupplier = shareDelegateSupplier;
+ mControlsState = controlsState;
mReadAloudControllerSupplier = readAloudControllerSupplier;
}
@@ -287,6 +295,17 @@
@Override
public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
mHelper.onGetContentRect(mode, view, outRect);
+ boolean controlsVisible = mControlsState.getBrowserControlHiddenRatio() < 1.f;
+ int controlsHeight = mControlsState.getTopControlsHeight();
+ if (controlsVisible && outRect.top < 2 * controlsHeight) {
+ // Make |outRect| taller to so the framework thinks there is not enough space
+ // above the selected text to place the floating action mode. This helps the action
+ // mode and the top controls avoid overlapping - the action mode will be positioned
+ // below the text.
+ // The right condition should be |outRect.top < controlsHeight + actionModeHeight|
+ // but we do not know |actionModeHeight|. Assume actionModeHeight ~= controlsHeight.
+ outRect.top -= controlsHeight;
+ }
}
private Set<String> getPackageNames(List<ResolveInfo> list) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
index 29173959..08cc31e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -843,6 +843,7 @@
},
showWebSearchInActionMode(),
mShareDelegateSupplier,
+ mBrowserControlsManager,
mReadAloudControllerSupplier);
mCaptureController =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
index b98108e..a08755e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
@@ -14,6 +14,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
@@ -35,6 +36,7 @@
import org.chromium.base.Callback;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
import org.chromium.chrome.browser.firstrun.FirstRunStatus;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.locale.LocaleManagerDelegate;
@@ -62,6 +64,7 @@
@Mock private Menu mMenu;
@Mock private ShareDelegate mShareDelegate;
@Mock private ReadAloudController mReadAloudController;
+ @Mock private BrowserControlsStateProvider mControlsState;
private class TestChromeActionModeCallback
extends ChromeActionModeHandler.ChromeActionModeCallback {
@@ -72,6 +75,7 @@
urlParams -> {},
true,
() -> mShareDelegate,
+ mControlsState,
() -> mReadAloudController);
}
@@ -237,6 +241,51 @@
verify(mReadAloudController).maybePauseForOutgoingIntent(eq(intent));
}
+ @Test
+ public void testAvoidOverlapWithTopControls() {
+ final int topControlsHeight = 150;
+ final int height = 80;
+ Mockito.when(mControlsState.getTopControlsHeight()).thenReturn(topControlsHeight);
+
+ // Set up for the case where top controls are hidden.
+ Mockito.when(mControlsState.getBrowserControlHiddenRatio()).thenReturn(1.f);
+
+ // If there's enough space between the selected text and the top of the content view for
+ // action mode, the content rect is left untouched.
+ int top = topControlsHeight * 3;
+ Rect outRect = new Rect(20, top, 500, top + height);
+ mActionModeCallback.onGetContentRect(mActionMode, null, outRect);
+ Assert.assertEquals(top, outRect.top);
+ Assert.assertEquals(height, outRect.height());
+
+ // Not enough space for action mode to fit in. The content rect is left untouched.
+ top = topControlsHeight;
+ outRect = new Rect(20, top, 500, top + height);
+ mActionModeCallback.onGetContentRect(mActionMode, null, outRect);
+ Assert.assertEquals(top, outRect.top);
+ Assert.assertEquals(height, outRect.height());
+
+ // Set up for the case where top controls are visible.
+ Mockito.when(mControlsState.getBrowserControlHiddenRatio()).thenReturn(0.f);
+
+ // We have enough space for action mode to fit in. The content rect is left untouched.
+ top = topControlsHeight * 3;
+ outRect = new Rect(20, top, 500, top + height);
+ mActionModeCallback.onGetContentRect(mActionMode, null, outRect);
+ Assert.assertEquals(top, outRect.top);
+ Assert.assertEquals(height, outRect.height());
+
+ // Not enough space for action mode to fit in. Verify that |onGetContentRect| bloated
+ // the content rect (top got taller) so action mode won't fit between the top controls
+ // and the selected text, therefore will be positioned below the text. This helps action
+ // mode avoid overlapping top controls.
+ top = topControlsHeight;
+ outRect = new Rect(20, top, 500, top + height);
+ mActionModeCallback.onGetContentRect(mActionMode, null, outRect);
+ Assert.assertEquals(top - topControlsHeight, outRect.top);
+ Assert.assertEquals(topControlsHeight + height, outRect.height());
+ }
+
private ResolveInfo createResolveInfo(String packageName) {
ResolveInfo resolveInfo = new ResolveInfo();
ActivityInfo activityInfo = new ActivityInfo();
Loading diff…
Original Bug Report
reported by ch...@gmail.com
Text Selection menu able to overlap URL bar
Steps to reproduce the problem
- Open the testcase.html or navigate to https://lbstyle.github.io/repro.html
- tap anywhere
Problem Description
When the user taps somewhere on the page, the text selection menu can appear over the URL bar, in this case, the user can be manipulated.
Summary
Text Selection menu able to overlap URL bar
Additional Data
Category: Security
Chrome Channel: Not sure
Regression: N/A
References
On This Page