【TaskbarDelegate】屏蔽上滑返回桌面手势功能

一、需求描述

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

二、需求分析

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

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

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

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

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

三、解决方案

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

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

privatefinalList<ComponentName> mHomeBlockingActivities =newArrayList<>();publicTaskbarDelegate(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);// 添加要屏蔽的 ActivityString[] disabledActivities = mContext.getResources().getStringArray(R.array.config_blockedHomeGestureActivities);for(String disabledActivity : disabledActivities){ mHomeBlockingActivities.add(ComponentName.unflattenFromString(disabledActivity));}}

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

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

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

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

privateboolean mIsHomeGestureBlocked;privatefinalTaskStackChangeListener mTaskStackListener =newTaskStackChangeListener(){@OverridepublicvoidonLockTaskModeChanged(int mode){ mSysUiState.setFlag(SYSUI_STATE_SCREEN_PINNING, mode == LOCK_TASK_MODE_PINNED).commitUpdate(mDisplayId);}@OverridepublicvoidonTaskStackChanged(){updateHomeGestureBlockState();}};privatevoidupdateHomeGestureBlockState(){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

privatevoidupdateSysuiFlags(){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 /*(mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0*/).setFlag(SYSUI_STATE_HOME_DISABLED, homeDisabled /*(mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0*/)//*/.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 的源码中处理,在 TouchInteractionServiceonInputEvent 方法中直接返回即可。

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

Read more

【降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码】

【降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码】

降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码_ide_葡萄城技术团队-葡萄城开发者空间 TRAE与Figma MCP:iOS原生应用UI自动生成的艺术-易源AI资讯 | 万维易源 Login | Figma 基于提供的Figma设计文件和网页链接,开发一个完整的前端网站项目。具体要求如下: 1. 页面展示要求: * 采用平铺式布局展示所有页面 * 严格遵循Figma设计稿中的视觉规范 * 实现IOS风格的高保真原型效果 * 确保所有交互元素与设计稿一致 2. 技术实现要求: * 使用现代前端框架(如React/Vue) * 实现响应式布局,适配不同设备 * 添加平滑的页面过渡动画 * 确保所有UI组件的高还原度 3. 交付物要求: * 完整的可运行前端代码 * 详细的部署文档 * 跨浏览器兼容性测试报告 * 性能优化方案 4. 质量标准: * 像素级还原设计稿 * 所有交互功能完整可用 * 代码符合最佳实践

Qwen3-VL-WEBUI视频理解能力实测:256K上下文部署实战

Qwen3-VL-WEBUI视频理解能力实测:256K上下文部署实战 1. 背景与技术定位 随着多模态大模型在视觉-语言任务中的广泛应用,对长上下文、高精度视频理解和复杂空间推理的需求日益增长。阿里云推出的 Qwen3-VL 系列模型,作为 Qwen 多模态家族的最新一代产品,标志着从“看懂图像”向“理解动态世界”的关键跃迁。 该系列基于开源项目 Qwen3-VL-WEBUI 提供了便捷的本地化部署方案,内置 Qwen3-VL-4B-Instruct 模型版本,支持单卡(如 RTX 4090D)即可运行,并原生支持高达 256K token 的上下文长度,可扩展至 1M,适用于长时间视频分析、文档结构解析和复杂代理任务执行。 本篇文章将围绕 Qwen3-VL-WEBUI 的实际部署流程、256K 长上下文处理能力、视频理解表现及工程优化建议展开深度实测,帮助开发者快速掌握其核心能力与落地路径。 2. 核心功能与技术升级详解 2.1 视觉-语言能力全面增强 Qwen3-VL

AI实体识别WebUI实战:基于RaNER的高效部署案例

AI实体识别WebUI实战:基于RaNER的高效部署案例 1. 引言:AI 智能实体侦测服务的现实需求 在信息爆炸的时代,非结构化文本数据(如新闻、社交媒体、客服对话)占据了企业数据总量的80%以上。如何从中快速提取关键信息,成为提升自动化处理效率的核心挑战。命名实体识别(Named Entity Recognition, NER)作为自然语言处理中的基础任务,承担着“信息抽取第一道工序”的角色。 传统人工标注成本高、效率低,而通用模型又难以满足中文语境下的精准识别需求。为此,达摩院推出的 RaNER 模型凭借其在中文新闻语料上的优异表现,成为构建高性能 NER 服务的理想选择。本文将深入介绍一个基于 RaNER 的 AI 实体识别 WebUI 部署实践案例,不仅实现高精度人名、地名、机构名自动抽取,还集成了具备视觉反馈能力的 Cyberpunk 风格 Web 界面,支持即写即测与

前端数据埋点

当我们想知道:“这个按钮有多少人点了?”、“用户在这个页面停留了多久?”、“哪个渠道来的用户转化率最高?”。 回答这些问题的核心技术手段,就是埋点(Tracking)。 一、什么是埋点?基本逻辑是什么? 1.1 定义 简单来说,埋点就是在特定的位置“埋”下一段代码或配置,当用户触发特定行为(如点击、浏览、输入)时,自动采集相关数据并发送到服务器的过程。 如果把网站比作一家超市,埋点就是安装在货架、收银台、门口的摄像头和传感器,记录顾客的行走路线、拿起商品的次数以及最终购买的行为。 1.2 基本逻辑流程 一个完整的埋点流程通常包含以下五个步骤: 1. 触发(Trigger): 用户产生行为(点击按钮、页面加载、接口请求等)。 2. 采集(Collect): 前端代码捕获该行为,并收集上下文信息(时间、URL、用户 ID、设备信息等)