You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AOSP中实现类似三星S-Pen的触控笔悬停指针?

实现低延迟触控笔悬停指针的AOSP集成方案

一、先确认底层输入事件基础

首先要确保触控笔硬件能正确上报悬停事件,这是低延迟的前提:

  • 用getevent -l命令验证输入设备输出:悬停状态下,设备应持续上报EV_ABS类的ABS_X/ABS_Y坐标,同时EV_KEY的BTN_TOUCH为0(未接触屏幕)、BTN_TOOL_PEN为1(检测到触控笔)。
  • 若驱动未上报悬停事件,需修改kernel驱动:让触控笔在悬停时持续发送坐标输入,同时为设备设置INPUT_PROP_POINTER属性,标记为指针类设备。

二、框架层输入事件优化(低延迟核心)

AOSP输入系统的延迟主要来自InputReader和InputDispatcher的处理逻辑,针对悬停事件做以下调整:

  • 事件识别修正:在frameworks/native/services/inputflinger/InputReader.cpp中,确保当BTN_TOUCH未触发但BTN_TOOL_PEN激活时,将事件标记为ACTION_HOVER_MOVE,避免被误归类为触摸事件过滤。
  • 关闭批量分发:在InputDispatcher.cpp中,针对触控笔设备单独禁用输入事件批量处理,调整DEFAULT_INPUT_DISPATCH_TIMEOUT为更低值(如1ms),减少事件排队延迟。
  • 窗口分发逻辑:修改WindowManagerService,确保悬停事件优先发送到顶层系统窗口(而非当前聚焦应用),实现全局指针显示的效果。

三、系统UI层实现悬停指针

通过系统级Overlay窗口绘制低延迟指针:

  • 创建全局Overlay窗口:使用TYPE_SYSTEM_OVERLAY类型窗口,设置FLAG_NOT_FOCUSABLE和FLAG_NOT_TOUCHABLE属性,避免干扰其他窗口输入。
  • 实时更新指针位置:在窗口的OnGenericMotionListener中监听ACTION_HOVER_MOVE事件,直接通过WindowManager.updateViewLayout更新坐标,跳过UI线程的异步队列。
  • 硬件加速绘制:用SurfaceView替代普通View绘制指针图标,利用SurfaceFlinger的硬件合成能力,避免软件渲染带来的延迟。

核心代码示例(系统级服务)

public class StylusHoverPointerService extends Service {
    private WindowManager mWindowManager;
    private SurfaceView mPointerView;
    private WindowManager.LayoutParams mLayoutParams;

    @Override
    public void onCreate() {
        super.onCreate();
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        
        // 初始化SurfaceView作为指针载体
        mPointerView = new SurfaceView(this);
        mPointerView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        // 绘制自定义悬停图标(可替换为S-Pen风格图标)
        Canvas canvas = mPointerView.getHolder().lockCanvas();
        if (canvas != null) {
            canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.stylus_hover), 0, 0, null);
            mPointerView.getHolder().unlockCanvasAndPost(canvas);
        }
        
        // 设置窗口参数
        mLayoutParams = new WindowManager.LayoutParams(
                dpToPx(32), dpToPx(32),
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT
        );
        mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
        mWindowManager.addView(mPointerView, mLayoutParams);
        
        // 监听悬停事件
        mPointerView.setOnGenericMotionListener((v, event) -> {
            if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
                mLayoutParams.x = (int) event.getRawX() - dpToPx(16);
                mLayoutParams.y = (int) event.getRawY() - dpToPx(16);
                mWindowManager.updateViewLayout(mPointerView, mLayoutParams);
                return true;
            }
            return false;
        });
    }

    private int dpToPx(int dp) {
        return (int) (dp * getResources().getDisplayMetrics().density);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mPointerView != null) {
            mWindowManager.removeView(mPointerView);
        }
    }
}

四、低延迟额外优化点

  • 权限与签名:系统级服务需android.permission.SYSTEM_ALERT_WINDOW权限,且必须以系统签名编译,否则无法创建Overlay窗口。
  • 驱动上报速率:调整触控笔驱动的事件上报频率至120Hz以上,减少坐标更新间隔。
  • 线程优先级:将处理悬停事件的线程设置为实时优先级(Process.THREAD_PRIORITY_URGENT_DISPLAY),避免被其他线程抢占资源。

内容的提问来源于stack exchange,提问作者anonymous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 03:05:48