Android 12:从 Editor 到 FloatingToolbar 全局收敛长按菜单

接上一篇在 ActivityStarter 侧拦截分享类 Activity 的做法:即便能挡住最终界面,客户仍希望 在 EditText、TextView、WebView 等长按文本时,弹出的浮动菜单里就不要出现「分享」「打开」「网页搜索」 ,避免用户习惯从菜单侧发起跳转。仅对单个应用设置 setCustomSelectionActionModeCallback 无法覆盖「所有应用」,因此需要在 Framework 层分两路处理:普通文本控件走 Editor,WebView 文本选择浮动条走 FloatingToolbar

为什么应用层方案不够用

网上常见示例是在应用里为 EditText 注册 setCustomSelectionActionModeCallback,自定义 ActionMode 菜单。该方式只能约束 自己写的界面,无法约束系统应用、第三方应用以及 WebView 内核菜单,因此本方案直接改 AOSP 文本编辑与浮动工具栏实现。


一、EditText / TextView:修改 Editor.java

路径: frameworks/base/core/java/android/widget/Editor.java

「分享」项由文本选择的 ActionMode / 上下文菜单 创建,与 TextView.ID_SHAREMENU_ITEM_ORDER_SHARE 等常量相关。做法有两类(与你们实际补丁一致即可):

在构建上下文菜单时,原逻辑会向 menu 注册 ID_SHARE。将整块注释掉,并加上说明注释,例如:

java 复制代码
// 屏蔽搜索(分享入口)
// menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE,
//         com.android.internal.R.string.share)
//         .setEnabled(mTextView.canShare())
//         .setOnMenuItemClickListener(mOnContextMenuClickListener);
menu.add(Menu.NONE, TextView.ID_SELECT_ALL, MENU_ITEM_ORDER_SELECT_ALL,
        com.android.internal.R.string.selectAll)

(中间保留粘贴、全选、自动填充等你们需要保留的项。)

在根据 canPaste() / canShare() 等向 Menu 添加条目时,将「分享」整段用块注释关闭,避免长按后工具栏仍出现分享:

java 复制代码
if (mTextView.canPaste()) {
    menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE,
            com.android.internal.R.string.paste)
            .setAlphabeticShortcut('v')
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}

/* // 屏蔽长按文本弹出来的分享按钮
if (mTextView.canShare()) {
    menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE,
            com.android.internal.R.string.share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
*/

if (mTextView.canRequestAutofill()) {
    final String selected = mTextView.getSelectedText();
    if (selected == null || selected.isEmpty()) {
        menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
                com.android.internal.R.string.autofill)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    }
}

注意: 注释掉分享后,若还有「网页搜索」等来自 WebView 内部浮动条 的项,需继续看第二节;纯 TextView 场景一般与 Editor 同步收敛即可。


二、WebView:在 FloatingToolbar.java 中过滤菜单

路径: frameworks/base/core/java/com/android/internal/widget/FloatingToolbar.java

调试可知:WebView 长按选中文本后出现的「打开」「分享」「网页搜索」等,多由 FloatingToolbar 在展示前组装菜单。在 doShow() 展示浮动条之前插入一次过滤,只保留复制、粘贴、全选、剪切等系统字符串标题对应的项,其余一律 setVisible(false)

1. 在 doShow() 开头调用过滤

java 复制代码
private void doShow() {
    removeRedundantMenu(mMenu); // 过滤掉不需要的弹出菜单
    List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
    menuItems.sort(mMenuItemComparator);
    // ... 后续 layout / show 逻辑不变
}

2. 新增 removeRedundantMenu 方法(示例)

通过标题与系统字符串资源比对,只保留基础编辑能力,隐藏「打开」「分享」「网页搜索」等扩展项:

java 复制代码
private void removeRedundantMenu(Menu menu) {
    int size = menu.size();
    for (int i = 0; i < size; i++) {
        MenuItem item = menu.getItem(i);
        if (mContext.getResources().getString(android.R.string.copy).equals(item.getTitle())
                || mContext.getResources().getString(android.R.string.paste).equals(item.getTitle())
                || mContext.getResources().getString(android.R.string.selectAll).equals(item.getTitle())
                || mContext.getResources().getString(android.R.string.cut).equals(item.getTitle())) {
            // 保留复制、粘贴、全选、剪切
        } else {
            item.setVisible(false);  // 隐藏其余菜单项
        }
    }
}

说明:

  • 若某些 ROM 或 WebView 版本把「打开」等做成了与系统字符串不完全一致的标题,需要再按 item.getItemId()title 关键字补充白名单/黑名单。
  • 过滤后若出现空菜单或异常,需在真机上覆盖 Chrome WebView、系统 WebView 与典型业务 H5 页回归。

三、联调与边界

层级 作用范围 典型风险
Editor 系统 TextView/EditText 系长按 需确认 SearchView、自定义 Editor 是否另有入口
FloatingToolbar WebView 等使用浮动工具栏的场景 不同语言下 title 可能本地化,需抽样验证
与上一篇配合 ActivityStarter 兜底 即使菜单漏出,仍可拦截最终 Activity
相关推荐
alexhilton5 小时前
Android车载OS中的Remote Compose
android·kotlin·android jetpack
落魄Android在线炒饭14 小时前
Android 自定义HAL开发篇之 HIDL篇——从入门到实战(上)
android
plainGeekDev15 小时前
广播接收器 → Flow + Lifecycle
android·java·kotlin
plainGeekDev15 小时前
EventBus → SharedFlow
android·java·kotlin
37手游移动客户端团队2 天前
招聘-高级安卓开发工程师
android·客户端
用户41659673693552 天前
WebView 请求异常排查操作手册
android·前端
Kapaseker2 天前
学不动了,入门 Compose Styles API
android·kotlin
墨狂之逸才2 天前
Android TV WebView 遥控器按键处理:从全透传到白名单
android
plainGeekDev3 天前
MVC 写法 → MVVM
android·java·kotlin
恋猫de小郭3 天前
Flutter Patchwork,不用 Fork 改依赖包源码的第三方工具
android·前端·flutter