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,就可以監聽全域觸摸事件,
其他系統環境可以根據實際情況參考上面的實作,
共勉:看得更多才知道還有更多還沒看過,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/298690.html
標籤:其他
上一篇:iOS逆向之初識匯編的基礎理論
