Android 全局手势识别原理

Android全局手势识别机制解析

本文是对全局手势识别进行分析,那什么是全局手势呢?简单来说就是在任何界面都需要识别的手势,比如:在任何界面从手机屏幕左侧滑动,当前的界面会退出 (类似 back 键)。

我们知道,在 Android 系统中一个 Activity 在显示时,当对屏幕触摸事件进行响应时,经过了许多逻辑处理,详细分析可以参考之前对 IMS 原理分析的一系列文章: Android知识体系导图 中的输入系统章节。

接下来对全局手势事件注册监听及处理进行分析。目前使用 12.0 代码分析

一 启动和注册 Native 监听

RootWindowContainer 的构造是在 WindowManagerService 中:

WindowManagerService.java 

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, DisplayWindowSettingsProvider
            displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
   
   
            ……
            mRoot = new RootWindowContainer(this);
			……
    }

可见 RootWindowContainer 对象作为 WindowManagerService 的成员变量 mRoot 存在。在 SystemServer 类的 startOtherServices 中,会调用 ActivityManagerService 的 setWindowManager() 方法:

SystemServer.java

mActivityManagerService.setWindowManager(wm);
ActivityManagerService.java

public void setWindowManager(WindowManagerService wm) {
   
   
1846          synchronized (this) {
   
   
1847              mWindowManager = wm;
1848              mWmInternal = LocalServices.getService(WindowManagerInternal.class);
1849              mActivityTaskManager.setWindowManager(wm);
1850          }
1851      }

进而调用 ActivityTaskManagerService 的 setWindowManager

ActivityTaskManagerService.java

    public void setWindowManager(WindowManagerService wm) {
   
   
974          synchronized (mGlobalLock) {
   
   
975              mWindowManager = wm;
976              mRootWindowContainer = wm.mRoot;
977              mTempConfig.setToDefaults();
978              mTempConfig.setLocales(LocaleList.getDefault());
979              mConfigurationSeq = mTempConfig.seq = 1;
980              mRootWindowContainer.onConfigurationChanged(mTempConfig);
981              mLockTaskController.setWindowManager(wm);
982              mTaskSupervisor.setWindowManager(wm);
983              mRootWindowContainer.setWindowManager(wm);
984          }
985      }

ActivityTaskManagerService 的成员变量 mRootWindowContainer 也赋值为 RootWindowContainer 根对象。最后会调用RootWindowContainer的setWindowManager(wm)方法:

RootWindowContainer.java 

    void setWindowManager(WindowManagerService wm) {
   
   
1353          mWindowManager = wm;
1354          mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
1355          mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
1356          mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
1357  
1358          final Display[] displays = mDisplayManager.getDisplays();
1359          for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
   
   
1360              final Display display = displays[displayNdx];
1361              final DisplayContent displayContent = new DisplayContent(display, this);
1362              addChild(displayContent, POSITION_BOTTOM);
1363              if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
   
   
1364                  mDefaultDisplay = displayContent;
1365              }
1366          }
1367          calculateDefaultMinimalSizeOfResizeableTasks();
1368  
1369          final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();
1370          defaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
1371          positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,
1372                  false /* includingParents */);
1373      }

从上面看出,通过屏幕管理对象 mDisplayManager 得到所有的显示屏幕,然后构造 DisplayContent 对象,再通过 addChild(displayContent, POSITION_BOTTOM) 方法将 DisplayContent 对象添加到 RootWindowContainer 根对象的树状结构中。

默认显示屏幕的 mDisplayId 是 DEFAULT_DISPLAY,看下它的值(Display类 public static final int DEFAULT_DISPLAY = 0),mDisplayId 为 0 作为基本显示屏幕。我们接下来看 DisplayContent 的构造函数。
  
在 DisplayContent.java 的构造函数中进行注册,代码如下:

DisplayContent.java 

    private final PointerEventDispatcher mPointerEventDispatcher;

    DisplayContent(Display display, RootWindowContainer root) {
   
    // 构造函数中初始化     
            ......
            final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
1028                  "PointerEventDispatcher" + mDisplayId, mDisplayId);
1029          mPointerEventDispatcher = new PointerEventDispatcher(inputChannel, this);
            ......
    }
}

我们可以看到在 DisplayContent 的构造函数中,生成了 InputChannel,并作为参数传入 PointerEventDispatcher 中。我们知道这个 InputChannel 就是一对负责通信的 socket 通道。至于构建过程我们后面分析,我们只要知道它是 socket 通信通道的建立即可。

接着上面的分析,在 DisplayContent 的构造方法内部,通过 mWmService.mInputManager.monitorInput() 的返回值 InputChannel,创建了PointerEventDispatcher对象,一起看一下PointerEventDispatcher的实现:

public class PointerEventDispatcher extends InputEventReceiver {
   
   
35      private final ArrayList<PointerEventListener> mListeners = new ArrayList<>();
36      private PointerEventListener[] mListenersArray = new PointerEventListener[0];
37  
38      private final DisplayContent mDisplayContent;
39      private final Point mTmpSize = new Point();
40  
41      public PointerEventDispatcher(InputChannel inputChannel, DisplayContent dc) {
   
   
42          super(inputChannel, UiThread.getHandler().getLooper());
43          mDisplayContent = dc;
44      }
45  
46      @Override
47      public void onInputEvent(InputEvent event) {
   
   
48          try {
   
   
49              if (event instanceof MotionEvent
50                      && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
   
   
51                  MotionEvent motionEvent = (MotionEvent) event;
52                  if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
   
   
53                      final int rotation = mDisplayContent.getRotation();
54                      if (rotation != Surface.ROTATION_0) {
   
   
55                          mDisplayContent.getDisplay().getRealSize(mTmpSize);
56                          motionEvent = MotionEvent.obtain(motionEvent);
57                          motionEvent.transform(MotionEvent.createRotateMatrix(
58                                  rotation, mTmpSize.x, mTmpSize.y));
59                      }
60                  }
61                  PointerEventListener[] listeners;
62                  synchronized (mListeners) {
   
   
63                      if (mListenersArray == null) {
   
   
64            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值