跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Android TaskbarDelegate 屏蔽上滑返回桌面手势

Android 14 平台下,通过修改 SystemUI 中 TaskbarDelegate 的逻辑,利用 TaskStackChangeListener 监听任务栈变化,动态设置 SYSUI_STATE_OVERVIEW_DISABLED 和 SYSUI_STATE_HOME_DISABLED 标志位,实现特定应用界面屏蔽上滑返回桌面手势的功能,无需拦截输入事件流。

芝士奶盖发布于 2026/4/6更新于 2026/9/1273 浏览

需求描述

基于 Android 14 平台,在应用界面中默认使用上滑手势会返回桌面,某些应用要求不能返回到桌面,需要屏蔽上滑手势。

需求分析

我们知道手势导航的底部导航横线的逻辑是在 SystemUI 的 NavigationBarView -> NavigationBar -> NavigationBarController -> TaskbarDelegate 等相关的类控制,在 手势导航 中上滑手势有 2 种功能:

  • 从屏幕底部向上滑动,即可进入主屏幕
  • 从底部向上滑动、按住再松开,可切换应用

如果想要屏蔽,可以直接返回消费掉 InputEvent 事件,就不会走后续的流程了。我尝试在 NavigationBarView 的 onInterceptTouchEvent 返回 true,但是只屏蔽了返回 Home 的功能,最近任务还是会启动。在 TaskbarDelegate 中有设置相关的 sys ui flag 的相关逻辑,于是我们可以参考类似方案,实现类似的屏蔽效果。

  1. TaskbarDelegate 初始化时添加需要屏蔽上滑功能的 Activity 合集
  2. 创建一个监听器 TaskStackChangeListener,用于监听前台应用是否需要屏蔽,并注册监听
  3. 任务栈变化时候改变 SysuiFlag,如 SYSUI_STATE_OVERVIEW_DISABLED 和 SYSUI_STATE_HOME_DISABLED

这个方案的优点是,我们不需要去追踪复杂的输入事件流,而是直接通过官方提供的、系统级的状态标志来声明我们的意图。InputDispatcher(负责分发所有触摸事件的底层服务)会尊重这些标志,并从源头上就阻止手势的发生。

解决方案

SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java

1. 添加需要屏蔽上滑功能的 Activity 合集

private final List<ComponentName> mHomeBlockingActivities = new ArrayList<>();

public TaskbarDelegate(Context context, LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
    mLightBarTransitionsControllerFactory = lightBarTransitionsControllerFactory;
    mContext = context;
    mDisplayManager = mContext.getSystemService(DisplayManager.class);
    mPipListener = (bounds) -> {
        mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
    };
    mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
    mStatusBarKeyguardViewManager.setTaskbarDelegate(this);
    // 添加要屏蔽的 Activity
    String[] disabledActivities = mContext.getResources().getStringArray(R.array.config_blockedHomeGestureActivities);
    for (String disabledActivity : disabledActivities) {
        mHomeBlockingActivities.add(ComponentName.unflattenFromString(disabledActivity));
    }
}

在新建的 config_blockedHomeGestureActivities 数组中添加需要屏蔽类名即可

<string-array name="config_blockedHomeGestureActivities">
    <item>com.android.deskclock/.DeskClock</item>
</string-array>

2. 注册并监听任务栈变化

TaskbarDelegate 原本逻辑中就包含了 TaskStackChangeListener 的监听,但是没有 onTaskStackChanged 的重写,只需要加上即可

private boolean mIsHomeGestureBlocked;
private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
    @Override
    public void onLockTaskModeChanged(int mode) {
        mSysUiState.setFlag(SYSUI_STATE_SCREEN_PINNING, mode == LOCK_TASK_MODE_PINNED).commitUpdate(mDisplayId);
    }

    @Override
    public void onTaskStackChanged() {
        updateHomeGestureBlockState();
    }
};

private void updateHomeGestureBlockState() {
    boolean shouldBlock = false;
    ActivityManager.RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask();
    ComponentName topActivity = runningTask == null ? null : runningTask.topActivity;
    shouldBlock = topActivity != null && mHomeBlockingActivities.contains(topActivity);
    if (mIsHomeGestureBlocked != shouldBlock) {
        mIsHomeGestureBlocked = shouldBlock;
        updateSysuiFlags();
    }
}

3. 更新标志位 updateSysuiFlags

private void updateSysuiFlags() {
    android.util.Log.e("maxx", "updateSysuiFlags");
    int a11yFlags = mNavBarHelper.getA11yButtonState();
    boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
    boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
    
    // 新增修改:
    boolean overviewDisabled = (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0 || mIsHomeGestureBlocked;
    boolean homeDisabled = (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0 || mIsHomeGestureBlocked;
    
    mSysUiState.setFlag(SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable)
        .setFlag(SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable)
        .setFlag(SYSUI_STATE_IME_SHOWING, (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
        .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING, (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0)
        // 新增修改:
        .setFlag(SYSUI_STATE_OVERVIEW_DISABLED, overviewDisabled)
        .setFlag(SYSUI_STATE_HOME_DISABLED, homeDisabled)
        .setFlag(SYSUI_STATE_BACK_DISABLED, (mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
        .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isWindowVisible())
        .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY, allowSystemGestureIgnoringBarVisibility())
        .setFlag(SYSUI_STATE_IMMERSIVE_MODE, isImmersiveMode())
        .commitUpdate(mDisplayId);
}

还有一种思路是在 Launcher 做屏蔽处理,例如在 Launcher3 的源码中处理,在 TouchInteractionService 的 onInputEvent 方法中直接返回即可。

Launcher3/quickstep/src/com/android/quickstep/TouchInteractionService.java
public void onInputEvent(InputEvent ev) {
    if (needInterceptHome()) {
        return;
    }
    ...
}

目录

  1. 需求描述
  2. 需求分析
  3. 解决方案

更多推荐文章

查看全部
  • Open WebUI 下载模型文件的默认存储路径
  • HarmonyOS Next DevEco Studio 端云一体化开发业务介绍
  • 清华团队发布 Vidu 大模型,支持 16 秒文生视频生成
  • 智元机器人三大产线详解与技术分析
  • GLM-5 全栈实战:从本地部署到多 Agent 架构应用
  • Robot Lab 基于 Isaac Lab 的机器人强化学习实战指南
  • 使用飞书 AI 知识库搭建个人技术文档系统
  • 初识Java:语言特性与基础语法入门
  • 网络安全:新手如何从零开始学习漏洞挖掘
  • 家庭 AI 助手实战:QQ 机器人接入 OpenClaw
  • 基于 Java 的外卖点餐系统设计与实现
  • Chaterm:AI 驱动的云资源管理终端实战指南
  • Linux 下 Git 版本控制基础与常用命令实战
  • Python 核心语法:Pandas 读写 CSV 与 TSV 文件
  • AI 产品经理数据标注全流程指南
  • Windows下MySQL 8.4压缩包安装手记
  • 鸿蒙 HarmonyOS 6 混合开发:ArkWeb 加载机制与 Cookie 管理
  • Python 多线程 SSH 文件传输工具设计与实现
  • 无人机航拍小目标检测:YOLO11 实战与 PyQt6 应用
  • WebStorm 安装与首次配置指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online