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_SHARE、MENU_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
相关推荐
墨天梦5 小时前
B17_LifecycleLiveData与Flow
android·kotlin
_祝你今天愉快7 小时前
UI核心 - 绘制流程(测量、布局、绘制)
android
冬奇Lab8 小时前
LLM 驱动的自动化测试系列(07):移动端自动化(三)——Mobile-Agent-v3 与自研 GUI-Owl 模型路线
android·人工智能·测试
leobertlan11 小时前
痛苦系列 | DSP-02 频域切片:DTFT与DFT的探索
android·后端
leobertlan12 小时前
痛苦系列 | DSP-01 从连续到离散:DSP基础与采样
android·后端
事圆则缓14 小时前
Android 视频压缩上传实战:从 content Uri、转码到断点续传
android
冉冉同学17 小时前
AI Agent 开始操作真实手机:移动端自动化的 3 个新考点
android·ai编程
帅得不敢出门18 小时前
Android Framework关闭软件低电关机功能测试PMIC低电保护
android
恋猫de小郭18 小时前
Flutter + EmbeddingGemma 2,谷歌发布完全端侧的 AI Edge Foresight
android·前端·flutter
墨天梦19 小时前
B16_Material主题与可访问交互
android·kotlin·交互