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
相关推荐
码龙-DragonCoding10 分钟前
一键批量提取音频、提取视频
android·音视频·提取
祉猷并茂,雯华若锦21 分钟前
Win下完美解决Allure报错,生成Web自动化测试报告
android·python·selenium·自动化
IT小盘2 小时前
08-FastAPI加MySQL实现AI对话记录持久化
android·mysql·fastapi
清泓y2 小时前
Android内存管理与性能优化面试真题
android·面试·性能优化
YF02113 小时前
Android compose详解
android
IT小码哥丶3 小时前
Android进阶之事件分发机制深度剖析
android
执明wa18 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
404_coder19 小时前
源码视角下的 Android 开机流程:从 Zygote、SystemServer 到 Launcher
android
二流小码农19 小时前
鸿蒙开发:以登录案例了解代码架构MVVM
android·ios·harmonyos
用户693717500138420 小时前
从代码生产者到 AI 协作者:软件工程师的角色重构
android·前端·后端