Android系统全局触摸事件监听

Posted 峥嵘life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统全局触摸事件监听相关的知识,希望对你有一定的参考价值。

android系统全局触摸事件监听

Android触摸全局监听指的是调用监听后在任何界面都能获取到触摸事件。

要实现这个功能必须要修改源码添加新的接口,因为系统默认是不暴露这个方法的。

监听系统全局触摸事件的类和相关代码:

frameworks\\base\\services\\core\\java\\com\\android\\server\\wm\\WindowManagerService.java
    @Override
    public void registerPointerEventListener(PointerEventListener listener, int displayId) {
        Slog.i(TAG, "registerPointerEventListener PointerEventListener = " + listener);
        synchronized (mGlobalLock) {
            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
            if (displayContent != null) {
                displayContent.registerPointerEventListener(listener);
            }
        }
    }

    @Override
    public void unregisterPointerEventListener(PointerEventListener listener, int displayId) {
        synchronized (mGlobalLock) {
            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
            if (displayContent != null) {
                displayContent.unregisterPointerEventListener(listener);
            }
        }
    }

第一个参数:是中PointerEventListener接口,

里面有MotionEvent对象含有点击事件,比如DOWN、UP、MOVING等其他信息。
    package android.view;
    public interface WindowManagerPolicyConstants {
        interface PointerEventListener {
            void onPointerEvent(MotionEvent motionEvent);
        }
    }

第二个参数,屏幕id,正常用0 ,表示主屏幕id。有些设备有投屏或者第二屏才需要关注这个。

下面介绍如何注册这个服务

1、绑定这个系统服务,这个方法行不通

因为这个服务的aidl接口IWindowManager,并没有暴露这个方法
registerPointerEventListener方法定义在另一个内部接口 WindowManagerFuncs 中

public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
    public interface WindowManagerFuncs {
            /** Register a system listener for touch events */
            void registerPointerEventListener(PointerEventListener listener, int displayId);

            /** Unregister a system listener for touch events */
            void unregisterPointerEventListener(PointerEventListener listener, int displayId);
    }
}

2、获取WindowManagerFuncs对象,该对象获取的方式在源码中有多种

参考:

frameworks\\base\\services\\core\\java\\com\\android\\server\\policy\\PhoneWindowManager.java
public PhoneWindowManager extends AbsPhoneWindowManager implements WindowManagerPolicy, IHwPhoneWindowManagerInner{
    public WindowManagerFuncs getWindowManagerFuncs(){
        return mWindowManagerFuncs; 
    }
}

WindowManagerFuncs在源码中是可以直接new的,使用如下:

PhoneWindowManager phoneWindowManager = new PhoneWindowManager();
WindowManagerFuncs windowManagerFuncs = phoneWindowManager.getWindowManagerFuncs();
windowManagerFuncsEx.registerPointerEventListener(listener, Display.DEFAULT_DISPLAY);

3、在华为Emui源码添加aidl回调

WindowManagerEx有通道直接发送数据到WindowManagerService并可以进行数据监听

(1)添加aidl接口

vendor\\huawei\\Emui\\frameworks\\hwCommInterface\\base\\core\\java\\com\\huawei\\android\\app\\IHwPointEventCallback.aidl
package com.huawei.android.app;
    import android.view.MotionEvent;
    oneway interface IHwPointEventCallback {
        void onPointerEvent(in MotionEvent motionEvent);
    }

(2)WindowManagerEx的修改

vendor\\huawei\\Emui\\frameworks\\hwext\\hwext\\framework\\src\\com\\huawei\\android\\app\\WindowManagerEx.java
    private final int TRANSACTION_SET_POINTER_EVENT_LISTENER = android.os.IBinder.FIRST_CALL_TRANSACTION + 2100;
    //给WindowManagerService传递监听对象
    public static void setPointerEventListener(IHwPointEventCallback listener) {
        Log.i(LOG_TAG, "setPointerEventListener listener = " + listener);
        IBinder windowManagerBinder = WindowManagerGlobal.getWindowManagerService().asBinder();
        if (windowManagerBinder != null) {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            try {
                data.writeInterfaceToken("android.view.IWindowManager");
                //传递aidl监听对象
                data.writeStrongBinder(listener != null ? listener.asBinder() : null);
               //发送
                windowManagerBinder.transact(TRANSACTION_SET_POINTER_EVENT_LISTENER, data, reply, 0);
            } catch (RemoteException e){
                Log.e(LOG_TAG, "setPointerEventListener exception is " + e.getMessage());
            } finally {
                data.recycle();
                reply.recycle();
            }
        } else {
            Log.w(LOG_TAG, "setPointerEventListener windowManagerBinder is null");
        }
    }

(3)在WindowManagerService中接收数据并做实际监听

基于尽量不修改源码的理念,Emui中有WindowManagerService的子类HwWindowManagerService,在子类中修改代码即可。

vendor\\huawei\\Emui\\frameworks\\base\\services\\java\\huawei\\com\\android\\server\\wm\\HwWindowManagerService.java
    HwWindowManagerService extends WindowManagerService
    private final int TRANSACTION_SET_POINTER_EVENT_LISTENER = android.os.IBinder.FIRST_CALL_TRANSACTION + 2100;
    private IHwPointEventCallback mIHwPointEventCallback = null;
    
    //接收WindowManagerEx传递过来的数据
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
            switch (code) {
                case TRANSACTION_SET_POINTER_EVENT_LISTENER:
                    data.enforceInterface("android.view.IWindowManager");
                    IHwPointEventCallback observer = IHwPointEventCallback.Stub.asInterface(data.readStrongBinder());
                    setPointerEventListener(observer);
                    reply.writeNoException();
                    return true;

        }
    }
    
    //在Service中创建唯一的监听对象
    private PointerEventListener mPointerEventListener = new PointerEventListener() {
        @Override
        public void onPointerEvent(MotionEvent motionEvent) {
            if(mIHwPointEventCallback != null) {
                try {
                    mIHwPointEventCallback.onPointerEvent(motionEvent);
                } catch (RemoteException e) {
                    Slog.e(TAG, "mIHwPointEventCallback error = " + e.getMessage());
                }
            }
        }
    };

    //添加设置触摸监听方法
    private void setPointerEventListener(IHwPointEventCallback listener) {
        Slog.i(TAG, "setPointerEventListener PointerEventListener = " + listener);
        int uid = Binder.getCallingUid();
        if(uid != Process.SYSTEM_UID){
            Slog.e(TAG, "setPointerEventListener uid must be "+ Process.SYSTEM_UID +",but now uid = " + uid);
            return;
        }
        mIHwPointEventCallback = listener;
        if(listener != null) {
            //实际调到父类的注册触摸事件的方法
            registerPointerEventListener(mPointerEventListener, Display.DEFAULT_DISPLAY);
        }
        else {
            //实际调到父类的反注册触摸事件的方法
            unregisterPointerEventListener(mPointerEventListener, Display.DEFAULT_DISPLAY);
        }
    }
方法3可以实现在普通app中监听到系统的全局触摸事件,

因为app可以依赖Emui的emui_addons.jar,
调用到里面的部分类,比如WindowManagerEx,就可以监听全局触摸事件。

其他系统环境可以根据实际情况参考上面的实现。

共勉:看得更多才知道还有更多还没看过。

以上是关于Android系统全局触摸事件监听的主要内容,如果未能解决你的问题,请参考以下文章

是否可以监听物理 Android 后退按钮的触摸?

Android 仿IOS边缘滑动事件监听

Android 仿IOS边缘滑动事件监听

Android:WebView 触摸事件监听器

Android 基于监听的事件处理机制详解

Android R PointerEventDispatcher 触摸事件监听帮助类