Android10添加 全局左右滑动返回

Android10添加 全局左右滑动返回


前言

android InputChannel;
android FD的概念


一、分析

1.全局监听是在SystemGesturesPointerEventListener.java中的
在DisplayPolicy的构造方法中,有new方法
mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
                new SystemGesturesPointerEventListener.Callbacks()
这就实现了全局的SystemGesturesPointerEventListener,
displayContent.registerPointerEventListener(mSystemGestures);这句就是监听传到 
在DisplayContent构造方法中,newDisplayPolicy对象
 mDisplayPolicy = new DisplayPolicy(service, this);    
 在看看构造方法传入的参数 DisplayContent(Display display, WindowManagerService service,
            ActivityDisplay activityDisplay)RootWindowContainer中新建的DisplayContent,
display是什么呢,就是显示,双屏或者外显的话 就是不同的display对象
           
      再看DisplayContent中方法
     void registerPointerEventListener(@NonNull PointerEventListener listener) {
        mPointerEventDispatcher.registerInputEventListener(listener);
    }
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
                "PointerEventDispatcher" + mDisplayId, mDisplayId);
        mPointerEventDispatcher = new PointerEventDispatcher(inputChannel);
     
     重点来了,点击触摸事件是怎么传递的, 重点就是这个InputChannel ,驱动事件就是通过这个来传递的,实际上,
     每个activity/window都是有InputChannel对象的, 那他们怎么通信的呢,这里先思考一下,这是不是属于android跨进程通信, 思考一下有哪些方法可以做到跨进程,这里毫无疑问 用的socket,快速,双工通信
     代码分析android.view.InputChannel.java  android.view.InputChannel.aidl
     android_view_InputChannel.cpp
     frameworks\native\libs\input\InputTransport.cpp
		status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.c_str(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    std::string serverChannelName = name;
    serverChannelName += " (server)";
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    clientChannelName += " (client)";
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

InputChannel::InputChannel(const std::string& name, int fd) :
        mName(name) {
#if DEBUG_CHANNEL_LIFECYCLE
    ALOGD("Input channel constructed: name='%s', fd=%d",
            mName.c_str(), fd);
#endif

    setFd(fd);
}

了解C++的同学,应该知道这里, 其实就相当于建立了socket通信,这也有一个关键点,文件描述符FD的概念,
做android的要记住一点,android基于linux,我对linux其实也是一知半解,但是linux有一个概念, 一切皆文件,
简单来说,这里有两个FD,通过这两个FD,两个文件之间建立了socket通信,这样就完成了事件的传递
	
这里就是分析一下点击触摸事件是怎么传递的,修改其实很简单

二、修改内容

1.修改内容

代码如下(示例):

diff --git a/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java b/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
index 43ccbcee3f..b5221ac51f 100644
--- a/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/alps/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -149,6 +149,7 @@ import android.view.InsetsState;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
 import android.view.Surface;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
@@ -481,6 +482,15 @@ public class DisplayPolicy {
                     @Override
                     public void onSwipeFromRight() {                                                
+                                               
+                                               long now = SystemClock.uptimeMillis();
+                                               KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0);
+                                               InputManager.getInstance().injectInputEvent(down, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+                                               KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0);
+                                               InputManager.getInstance().injectInputEvent(up, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+
+
+
                         final Region excludedRegion;
                         synchronized (mLock) {
                             excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
@@ -496,6 +506,13 @@ public class DisplayPolicy {
                     @Override
                     public void onSwipeFromLeft() {                                               
+                                               
+                                               long now = SystemClock.uptimeMillis();
+                                               KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0);
+                                               InputManager.getInstance().injectInputEvent(down, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+                                               KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0);
+                                               InputManager.getInstance().injectInputEvent(up, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+                                               
                         final Region excludedRegion;
                         synchronized (mLock) {
                             excludedRegion = mDisplayContent.calculateSystemGestureExclusion();

2.分析

这里其实写返回键的代码,可以参考systemui的KeyButtonView.java中

private void sendEvent(int action, int flags, long when) {
        mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
                .setType(MetricsEvent.TYPE_ACTION)
                .setSubtype(mCode)
                .addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
                .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
        // TODO(b/122195391): Added logs to make sure sysui is sending back button events
        if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
            Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
            if (action == MotionEvent.ACTION_UP) {
                mOverviewProxyService.notifyBackAction((flags & KeyEvent.FLAG_CANCELED) == 0,
                        -1, -1, true /* isButton */, false /* gestureSwipeLeft */);
            }
        }
        final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
        final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
                0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                InputDevice.SOURCE_KEYBOARD);

        int displayId = INVALID_DISPLAY;

        // Make KeyEvent work on multi-display environment
        if (getDisplay() != null) {
            displayId = getDisplay().getDisplayId();
        }
        // Bubble controller will give us a valid display id if it should get the back event
        BubbleController bubbleController = Dependency.get(BubbleController.class);
        int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);
        if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
            displayId = bubbleDisplayId;
        }
        if (displayId != INVALID_DISPLAY) {
            ev.setDisplayId(displayId);
        }
        mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
    }

中间的一大堆就可以不用看了, 看在哪里调用的sendEvent方法;
onTouchEvent中 
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
以及最后一句
 mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
 这就相当于发送了返回键的键值
 adb shell input keyevent 4
 第二种方法,runtime发送adb命令 ,这个自己百度

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuyewen288

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值