From 57c2fb6bb53061204ea66f6a8b75ca70018587b4 Mon Sep 17 00:00:00 2001 From: samartnik <30602739+samartnik@users.noreply.github.com> Date: Fri, 18 Jul 2025 08:14:58 -0400 Subject: [PATCH] [Android] Remove `Copy link` menu item from long press menu (#29954) --- android/java/apk_for_test.flags | 8 ++ .../chromium/chrome/browser/BytecodeTest.java | 12 ++ android/junit/BUILD.gn | 9 ++ ...veToolbarLongPressMenuHandlerUnitTest.java | 111 ++++++++++++++++++ browser/ui/android/toolbar/BUILD.gn | 22 ++++ .../BraveToolbarLongPressMenuHandler.java | 59 ++++++++++ build/android/bytecode/BUILD.gn | 1 + .../org/brave/bytecode/BraveClassAdapter.java | 1 + ...olbarLongPressMenuHandlerClassAdapter.java | 22 ++++ build/android/config.gni | 1 + test/BUILD.gn | 1 + 11 files changed, 247 insertions(+) create mode 100644 android/junit/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandlerUnitTest.java create mode 100644 browser/ui/android/toolbar/BUILD.gn create mode 100644 browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler.java create mode 100644 build/android/bytecode/java/org/brave/bytecode/BraveToolbarLongPressMenuHandlerClassAdapter.java diff --git a/android/java/apk_for_test.flags b/android/java/apk_for_test.flags index 9c05e4af1fc..347d062f7fa 100644 --- a/android/java/apk_for_test.flags +++ b/android/java/apk_for_test.flags @@ -995,3 +995,11 @@ -keep class org.chromium.chrome.browser.infobar.BraveInfoBarContainerView { (...); } + +-keep class org.chromium.chrome.browser.toolbar.ToolbarLongPressMenuHandler { + public (...); +} + +-keep class org.chromium.chrome.browser.toolbar.BraveToolbarLongPressMenuHandler { + public (...); +} diff --git a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java index 0997c68ec30..d4ffaee7fd7 100644 --- a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java +++ b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java @@ -1952,6 +1952,18 @@ public class BytecodeTest { BrowserControlsStateProvider.class, ObservableSupplier.class, boolean.class)); + Assert.assertTrue( + constructorsMatch( + "org/chromium/chrome/browser/toolbar/ToolbarLongPressMenuHandler", + "org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler", + Context.class, + ObservableSupplier.class, + boolean.class, + BooleanSupplier.class, + ActivityLifecycleDispatcher.class, + WindowAndroid.class, + java.util.function.Supplier.class, + java.util.function.Supplier.class)); } @Test diff --git a/android/junit/BUILD.gn b/android/junit/BUILD.gn index e362b9f2def..a2cb9a50d9f 100644 --- a/android/junit/BUILD.gn +++ b/android/junit/BUILD.gn @@ -22,4 +22,13 @@ if (is_android) { deps = [ "//chrome/android/junit:chrome_junit_tests_helper" ] } + + robolectric_library("brave_junit_tests_org.chromium.chrome.browser.toolbar") { + sources = [ "src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandlerUnitTest.java" ] + + deps = [ + "//brave/browser/ui/android/toolbar:java", + "//chrome/android/junit:chrome_junit_tests_helper", + ] + } } diff --git a/android/junit/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandlerUnitTest.java b/android/junit/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandlerUnitTest.java new file mode 100644 index 00000000000..25a77f1f54c --- /dev/null +++ b/android/junit/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandlerUnitTest.java @@ -0,0 +1,111 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.toolbar; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.app.Activity; +import android.content.pm.PackageManager; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; +import org.robolectric.Shadows; +import org.robolectric.shadows.ShadowPackageManager; + +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.Features.EnableFeatures; +import org.chromium.base.test.util.Restriction; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.ui.base.DeviceFormFactor; +import org.chromium.ui.base.TestActivity; +import org.chromium.ui.base.WindowAndroid; +import org.chromium.ui.display.DisplayAndroid; +import org.chromium.ui.listmenu.ListMenuItemProperties; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; +import org.chromium.ui.widget.ViewRectProvider; + +import java.util.function.BooleanSupplier; + +/** Unit tests for {@link BraveToolbarLongPressMenuHandler}. */ +@RunWith(BaseRobolectricTestRunner.class) +@EnableFeatures(ChromeFeatureList.ANDROID_BOTTOM_TOOLBAR) +public final class BraveToolbarLongPressMenuHandlerUnitTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(TestActivity.class); + + @Mock private ViewRectProvider mViewRectProvider; + @Mock Profile mProfile; + @Mock private WindowAndroid mWindowAndroid; + @Mock private ActivityLifecycleDispatcher mActivityLifecycleDispatcher; + @Mock private DisplayAndroid mDisplayAndroid; + + private ToolbarLongPressMenuHandler mToolbarLongPressMenuHandler; + private ObservableSupplierImpl mProfileSupplier; + + private Activity mActivity; + private boolean mShouldSuppress; + private final BooleanSupplier mSuppressSupplier = () -> mShouldSuppress; + private String mUrlString; + + @Before + public void setUp() throws Exception { + mActivity = Robolectric.buildActivity(Activity.class).get(); + ShadowPackageManager shadowPackageManager = Shadows.shadowOf(mActivity.getPackageManager()); + shadowPackageManager.setSystemFeature(PackageManager.FEATURE_SENSOR_HINGE_ANGLE, false); + + mProfileSupplier = new ObservableSupplierImpl<>(); + mProfileSupplier.set(mProfile); + + doReturn(mDisplayAndroid).when(mWindowAndroid).getDisplay(); + doReturn(1.0f).when(mDisplayAndroid).getDipScale(); + doReturn(true).when(mActivityLifecycleDispatcher).isNativeInitializationFinished(); + mToolbarLongPressMenuHandler = + new BraveToolbarLongPressMenuHandler( + mActivity, + mProfileSupplier, + false, + mSuppressSupplier, + mActivityLifecycleDispatcher, + mWindowAndroid, + () -> mUrlString, + () -> mViewRectProvider); + + verify(mActivityLifecycleDispatcher).register(mToolbarLongPressMenuHandler); + } + + @Test + @SmallTest + @Restriction({DeviceFormFactor.PHONE}) + public void testbuildMenuItems() { + ModelList list = mToolbarLongPressMenuHandler.buildMenuItems(true); + + assertEquals(1, list.size()); + assertEquals( + R.string.toolbar_move_to_the_bottom, + list.get(0).model.get(ListMenuItemProperties.TITLE_ID)); + assertEquals( + ToolbarLongPressMenuHandler.MenuItemType.MOVE_ADDRESS_BAR_TO, + list.get(0).model.get(ListMenuItemProperties.MENU_ITEM_ID)); + } +} diff --git a/browser/ui/android/toolbar/BUILD.gn b/browser/ui/android/toolbar/BUILD.gn new file mode 100644 index 00000000000..69addeac24b --- /dev/null +++ b/browser/ui/android/toolbar/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2025 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +import("//build/config/android/config.gni") +import("//build/config/android/rules.gni") +import("//chrome/browser/buildflags.gni") +import("//extensions/buildflags/buildflags.gni") +import("//third_party/jni_zero/jni_zero.gni") + +android_library("java") { + sources = [ "java/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler.java" ] + + deps = [ + "//base:supplier_java", + "//chrome/browser/android/lifecycle:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/ui/android/toolbar:java", + "//ui/android:ui_no_recycler_view_java", + ] +} diff --git a/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler.java b/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler.java new file mode 100644 index 00000000000..dfc9ae83e13 --- /dev/null +++ b/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler.java @@ -0,0 +1,59 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.toolbar; + +import android.content.Context; + +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.build.annotations.NullMarked; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.ui.base.WindowAndroid; +import org.chromium.ui.listmenu.ListMenuItemProperties; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; +import org.chromium.ui.widget.ViewRectProvider; + +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +/** Brave's extension for the handler for the toolbar long press menu. */ +@NullMarked +public class BraveToolbarLongPressMenuHandler extends ToolbarLongPressMenuHandler { + public BraveToolbarLongPressMenuHandler( + Context context, + ObservableSupplier profileSupplier, + boolean isCustomTab, + BooleanSupplier suppressLongPressSupplier, + ActivityLifecycleDispatcher lifecycleDispatcher, + WindowAndroid windowAndroid, + Supplier urlBarTextSupplier, + Supplier urlBarViewRectProviderSupplier) { + super( + context, + profileSupplier, + isCustomTab, + suppressLongPressSupplier, + lifecycleDispatcher, + windowAndroid, + urlBarTextSupplier, + urlBarViewRectProviderSupplier); + } + + @Override + ModelList buildMenuItems(boolean onTop) { + ModelList itemList = super.buildMenuItems(onTop); + + // Remove the "Copy link" item from menu. + for (int i = 0; i < itemList.size(); i++) { + int itemID = itemList.get(i).model.get(ListMenuItemProperties.MENU_ITEM_ID); + if (itemID == MenuItemType.COPY_LINK) { + itemList.removeAt(i); + break; + } + } + return itemList; + } +} diff --git a/build/android/bytecode/BUILD.gn b/build/android/bytecode/BUILD.gn index c118a998cb4..467374dd10c 100644 --- a/build/android/bytecode/BUILD.gn +++ b/build/android/bytecode/BUILD.gn @@ -127,6 +127,7 @@ java_binary("java_bytecode_rewriter") { "//brave/build/android/bytecode/java/org/brave/bytecode/BraveThemeUtilsClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveTileViewClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveToolbarLayoutClassAdapter.java", + "//brave/build/android/bytecode/java/org/brave/bytecode/BraveToolbarLongPressMenuHandlerClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveToolbarManagerClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveToolbarPositionControllerClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveToolbarSwipeLayoutClassAdapter.java", diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java index 54786a6efc1..0d19cacdb62 100644 --- a/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java +++ b/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java @@ -122,6 +122,7 @@ public class BraveClassAdapter { chain = new BraveThemeUtilsClassAdapter(chain); chain = new BraveTileViewClassAdapter(chain); chain = new BraveToolbarLayoutClassAdapter(chain); + chain = new BraveToolbarLongPressMenuHandlerClassAdapter(chain); chain = new BraveToolbarManagerClassAdapter(chain); chain = new BraveToolbarPositionControllerClassAdapter(chain); chain = new BraveToolbarSwipeLayoutClassAdapter(chain); diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveToolbarLongPressMenuHandlerClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveToolbarLongPressMenuHandlerClassAdapter.java new file mode 100644 index 00000000000..fee37477ff7 --- /dev/null +++ b/build/android/bytecode/java/org/brave/bytecode/BraveToolbarLongPressMenuHandlerClassAdapter.java @@ -0,0 +1,22 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +package org.brave.bytecode; + +import org.objectweb.asm.ClassVisitor; + +public class BraveToolbarLongPressMenuHandlerClassAdapter extends BraveClassVisitor { + static String sToolbarLongPressMenuHandlerClassName = + "org/chromium/chrome/browser/toolbar/ToolbarLongPressMenuHandler"; + static String sBraveToolbarLongPressMenuHandlerClassName = + "org/chromium/chrome/browser/toolbar/BraveToolbarLongPressMenuHandler"; + + public BraveToolbarLongPressMenuHandlerClassAdapter(ClassVisitor visitor) { + super(visitor); + + redirectConstructor( + sToolbarLongPressMenuHandlerClassName, sBraveToolbarLongPressMenuHandlerClassName); + } +} diff --git a/build/android/config.gni b/build/android/config.gni index 920d94477fd..f93d878f5bc 100644 --- a/build/android/config.gni +++ b/build/android/config.gni @@ -33,6 +33,7 @@ brave_chrome_java_deps = [ "//brave/browser/ui/android/logo:java", "//brave/browser/ui/android/omnibox:java", "//brave/browser/ui/android/theme:java", + "//brave/browser/ui/android/toolbar:java", "//brave/components/ai_chat/core/common/mojom:mojom_java", "//brave/components/brave_news/common:mojom_java", "//brave/components/brave_rewards/core/mojom:mojom_java", diff --git a/test/BUILD.gn b/test/BUILD.gn index cf7c7472a7a..1ff6dd82e6c 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1386,6 +1386,7 @@ if (is_android) { deps = [ "//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.homepage", "//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.tabbed_mode", + "//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.toolbar", ] } } # if (is_android) {