在车载开发中,有一个常见的需求就是各种手势控制中控与仪表的交互。
我们需要获取全局的Touch事件,然后解析手势,做对应的动作。这里有个最简单的获取全局Touch事件的方法。
framework
1.frameworks\base\services\core\java\com\android\server\wm\ TaskTapPointerEventListener.java
Android自己就用到了全局触摸的一个事件,所有的触摸事件除了会发送给应用进程窗口,同时也会发送到PointerEventDispatcher中来。
public class TaskTapPointerEventListener implements PointerEventListener {
...省略代码
public TaskTapPointerEventListener(WindowManagerService service,
DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
}
@Override
public void onPointerEvent(MotionEvent motionEvent, int displayId) {
if (displayId == getDisplayId()) {
onPointerEvent(motionEvent);
}
}
@Override
public void onPointerEvent(MotionEvent motionEvent) {
...省略代码
}
void setTouchExcludeRegion(Region newRegion) {
synchronized (this) {
mTouchExcludeRegion.set(newRegion);
}
}
private int getDisplayId() {
return mDisplayContent.getDisplayId();
}
}
2.frameworks/base/core/java/android/view/WindowManagerPolicyConstants.java
这个常量交互类里面定义了PointerEventListener。
public interface WindowManagerPolicyConstants {
// TODO: move this to a more appropriate place.
interface PointerEventListener {
/**
* 1. onPointerEvent will be called on the service.UiThread.
* 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
* copy() must be made and the copy must be recycled.
**/
void onPointerEvent(MotionEvent motionEvent);
/**
* @see #onPointerEvent(MotionEvent)
**/
default void onPointerEvent(MotionEvent motionEvent, int displayId) {
if (displayId == DEFAULT_DISPLAY) {
onPointerEvent(motionEvent);
}
}
}
}
3.frameworks\base\core\java\android\view\IWindowManager.aidl
需要在这个aidl接口里面将全局的PointerEventListener接口注册暴露出来。
/**
* Notify WindowManager that it should not override the info in DisplayManager for the specified
* display. This can disable letter- or pillar-boxing applied in DisplayManager when the metrics
* of the logical display reported from WindowManager do not correspond to the metrics of the
* physical display it is based on.
*
* @param displayId The id of the display.
*/
void dontOverrideDisplayInfo(int displayId);
/* add PointerEventListener */
void registerPointerEventListener(int displayId, IPointerEventListener listener);
void unregisterPointerEventListener(IPointerEventListener listener);
/* add PointerEventListener*/
4.frameworks\base\core\java\android\view\WindowManagerImpl.java
客户端处理IWindowManager aidl
public final class WindowManagerImpl implements WindowManager {
...省略代码
@Override
public void registerPointerEventListener(int displayId, IPointerEventListener listener) {
try {
WindowManagerGlobal.getWindowManagerService().registerPointerEventListener(displayId, listener);
} catch (RemoteException e) {
}
}
@Override
public void unregisterPointerEventListener(IPointerEventListener listener) {
try {
WindowManagerGlobal.getWindowManagerService().unregisterPointerEventListener(listener);
} catch (RemoteException e) {
}
}
...省略代码
}
5.frameworks\base\core\java\android\view\IPointerEventListener.aidl
自己创建对app暴露的接口
package android.view;
import android.view.MotionEvent;
/** @hide */
oneway interface IPointerEventListener {
void onPointerEvent(in MotionEvent motionEvent);
}
6.frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
在服务端我们需要自己注册一个PointerEventListener 把数据通过aidl传到 WindowManagerImpl
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
//添加远程列表
private RemoteCallbackList<IPointerEventListener> mPointerEventListeners = new RemoteCallbackList<>();
//在构造的方法里面注册
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
...省略代码
if (mPointerEventDispatcher != null) {
//因为我们外部的app用这个全局的触摸事件,所以这里注册我们自己的listener
mPointerEventDispatcher.registerInputEventListener(mListener);
}
...省略代码
}
private PointerEventListener mListener = new PointerEventListener() {
@Override
public void onPointerEvent(MotionEvent motionEvent) {
Slog.d(TAG, "onPointerEvent motionEvent: " + motionEvent);
}
@Override
public void onPointerEvent(MotionEvent motionEvent, int displayId) {
if (DEBUG_INPUT) {
Slog.d(TAG, "onPointerEvent displayId: " + displayId + " motionEvent: " + motionEvent);
}
int i = mPointerEventListeners.beginBroadcast();
while (i > 0) {
i--;
int cookie = (int) mPointerEventListeners.getBroadcastCookie(i);
if (cookie == displayId) {
try {
mPointerEventListeners.getBroadcastItem(i).onPointerEvent(motionEvent);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
mPointerEventListeners.finishBroadcast();
}
};
@Override
public void registerPointerEventListener(int displayId, IPointerEventListener listener) {
Slog.d(TAG, "registerPointerEventListener displayId: " + displayId + " listener: " + listener);
mPointerEventListeners.register(listener, displayId);
}
@Override
public void unregisterPointerEventListener(IPointerEventListener listener) {
Slog.d(TAG, "unregisterPointerEventListener listener: " + listener);
mPointerEventListeners.unregister(listener);
}
}
app
public class TouchManager extends IPointerEventListener.Stub {
WindowManager mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
@Override
public void onPointerEvent(MotionEvent motionEvent) throws RemoteException {
int action = motionEvent.getAction();
}
public void registerListener() {
try {
if (mWindowManager != null) {
Log.e(TAG, "registerPointerEventListener");
mWindowManager.registerPointerEventListener(Display.DEFAULT_DISPLAY, this);
}
} catch (Exception e) {
Log.e(TAG, "not connected!", e);
}
}
public void unRegisterListener() {
try {
if (mWindowManager != null) {
Log.e(TAG, "unRegisterListener");
mWindowManager.unregisterPointerEventListener(this);
}
} catch (Exception e) {
Log.e(TAG, "not connected!", e);
}
}
}