本文是对全局手势识别进行分析,那什么是全局手势呢?简单来说就是在任何界面都需要识别的手势,比如:在任何界面从手机屏幕左侧滑动,当前的界面会退出 (类似 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
Android全局手势识别机制解析

最低0.47元/天 解锁文章
500

被折叠的 条评论
为什么被折叠?



