在android 13 添加一个通过回调 监听、拦截触摸和按键的接口
添加回调接口
frameworks/base/core/java/android/hardware/input/IInputEventListener.aidl
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.input;
import android.view.InputEvent;
import android.view.KeyEvent;
interface IInputEventListener {
boolean interceptMotionBeforeQueueing(in InputEvent event,int mode);
int interceptKeyBeforeQueueing(in KeyEvent event,int policyFlags);
}
让lint检查忽略掉自己的模块
注(Android 11 以后谷歌强制开启lint检查,lint检查不过编译会报错)(参考文章)
frameworks/base/Android.bp
@@ -486,6 +486,7 @@ java_library {
// TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp
metalava_framework_docs_args = "" +
+ "--api-lint-ignore-prefix android.hardware.input. " + // 24.08.20 -- start
"--api-lint-ignore-prefix android.icu. " +
"--api-lint-ignore-prefix java. " +
"--api-lint-ignore-prefix junit. " +
实现注册回调&监听逻辑
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
@@ -148,6 +148,10 @@ import java.util.Objects;
import java.util.OptionalInt;
import java.util.function.Consumer;
+/* 24.06.27 -- start */
+import android.hardware.input.IInputEventListener;
+/* 24.06.27 -- end */
+
/** The system implementation of {@link IInputManager} that manages input devices. */
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor {
@@ -218,6 +222,11 @@ public class InputManagerService extends IInputManager.Stub
private final List<SensorEventListenerRecord> mSensorAccuracyListenersToNotify =
new ArrayList<>();
+ /* 24.06.27 -- start */
+ private final SparseArray<IInputEventListener> mInputEventListeners =
+ new SparseArray<IInputEventListener>();
+ /* 24.06.27 -- end */
+
// Persistent data store. Must be locked each time during use.
private final PersistentDataStore mDataStore = new PersistentDataStore();
@@ -2231,6 +2240,82 @@ public class InputManagerService extends IInputManager.Stub
}
}
+
+ /* 24.06.27 -- start */
+ @Override
+ public void registerInputEventListener(IInputEventListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mInputEventListeners) {
+ //final int callingPid = UserHandle.getCallingUserId();
+ int callingPid = Binder.getCallingPid();
+ Slog.d(TAG, "1813 registerInputEventListener:" + callingPid);
+ if (mInputEventListeners.get(callingPid) != null) {
+ Slog.d(TAG, "registerInputEventListener already registered:" + callingPid);
+ return;
+ }
+ mInputEventListeners.put(callingPid, listener);
+ }
+ }
+
+ @Override
+ public void unregisterInputEventListener(IInputEventListener listener) {
+ synchronized (mInputEventListeners) {
+ //final int callingPid = UserHandle.getCallingUserId();
+ int callingPid = Binder.getCallingPid();
+ Slog.d(TAG, "unregisterInputEventListener:" + callingPid);
+ mInputEventListeners.remove(callingPid);
+ }
+ }
+
+ private boolean interceptMotionBefore(InputEvent event,int mode) {
+ synchronized (mInputEventListeners) {
+ //遍历mInputEventListeners
+ for (int i = mInputEventListeners.size() - 1; i >= 0; i--) {
+ final int callingPid = mInputEventListeners.keyAt(i);
+ final IInputEventListener listener = mInputEventListeners.valueAt(i);
+ if (listener == null) {
+ continue;
+ }
+ try {
+ if(listener.interceptMotionBeforeQueueing(event, mode))
+ return true;
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + callingPid +
+ " that input event occurred, assuming it died.", ex);
+ mInputEventListeners.remove(callingPid);
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int interceptKeyBefore(KeyEvent event, int policyFlags) {
+ synchronized (mInputEventListeners) {
+ //遍历mInputEventListeners
+ for (int i = mInputEventListeners.size() - 1; i >= 0; i--) {
+ final int callingPid = mInputEventListeners.keyAt(i);
+ final IInputEventListener listener = mInputEventListeners.valueAt(i);
+ if (listener == null) {
+ continue;
+ }
+ try {
+ return listener.interceptKeyBeforeQueueing(event, policyFlags);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + callingPid +
+ " that input event occurred, assuming it died.", ex);
+ mInputEventListeners.remove(callingPid);
+ }
+ }
+ }
+ return 1;
+ }
+
+ /* 24.06.27 -- end */
+
// Native callback.
@SuppressWarnings("unused")
private void notifyVibratorState(int deviceId, boolean isOn) {
@@ -2998,9 +3083,19 @@ public class InputManagerService extends IInputManager.Stub
return true;
}
+ /* 24.07.22 -- start */
+ // Native callback.
+ private boolean interceptMotionBeforeQueueing(InputEvent event, int policyFlags) {
+ return interceptMotionBefore(event, policyFlags);
+ }
+ /* 24.07.22 -- end */
+
// Native callback.
@SuppressWarnings("unused")
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ /* 24.06.29 -- start */
+ if(interceptKeyBefore(event, policyFlags) == 0)return 0;
+ /* 24.06.29 -- start */
return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
实现新增的interceptMotionBeforeQueueing
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -102,6 +102,9 @@ static struct {
jmethodID notifyVibratorState;
jmethodID notifyUntrustedTouch;
jmethodID filterInputEvent;
+ /* 24.08.20 -- start*/
+ jmethodID interceptMotionBeforeQueueing;
+ /* 24.08.20 -- end*/
jmethodID interceptKeyBeforeQueueing;
jmethodID interceptMotionBeforeQueueingNonInteractive;
jmethodID interceptKeyBeforeDispatching;
@@ -323,6 +326,9 @@ public:
void notifyVibratorState(int32_t deviceId, bool isOn) override;
void notifyUntrustedTouch(const std::string& obscuringPackage) override;
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
+ /* 24.07.22 -- start */
+ virtual bool interceptMotionBeforeQueueing(const InputEvent* inputEvent, uint32_t policyFlags);
+ /* 24.07.22 -- end */
void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) override;
void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
@@ -1213,6 +1219,35 @@ bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t
return pass;
}
+/* 24.07.22 -- start */
+bool NativeInputManager::interceptMotionBeforeQueueing(const InputEvent* inputEvent, uint32_t policyFlags){
+ ATRACE_CALL();
+
+ jobject inputEventObj;
+
+ JNIEnv* env = jniEnv();
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY:
+ inputEventObj = android_view_KeyEvent_fromNative(env,
+ static_cast<const KeyEvent*>(inputEvent));
+ break;
+ case AINPUT_EVENT_TYPE_MOTION:
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<const MotionEvent*>(inputEvent));
+ break;
+ default:
+ return false; // dispatch the event normally
+ }
+
+ jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.interceptMotionBeforeQueueing,
+ inputEventObj, policyFlags);
+ if (checkAndClearExceptionFromCallback(env,"interceptMotionBeforeQueueing")) {
+ pass = false;
+ }
+ return pass;
+}
+/* 24.07.22 -- end */
+
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
ATRACE_CALL();
@@ -2463,6 +2498,11 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
"filterInputEvent", "(Landroid/view/InputEvent;I)Z");
+ /* 24.07.22 -- start */
+ GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueing, clazz,
+ "interceptMotionBeforeQueueing", "(Landroid/view/InputEvent;I)Z");
+ /* 24.07.22 -- end */
+
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
"interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4015,17 +4015,39 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
std::to_string(t.duration().count()).c_str());
}
+ /* 24.07.22 -- start */
+ ui::Transform displayTransform;
+ if (const auto it = mDisplayInfos.find(args->displayId); it != mDisplayInfos.end()) {
+ displayTransform = it->second.transform;
+ }
+ MotionEvent event;
+ event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
+ args->action, args->actionButton, args->flags, args->edgeFlags,
+ args->metaState, args->buttonState, args->classification,
+ displayTransform, args->xPrecision, args->yPrecision,
+ args->xCursorPosition, args->yCursorPosition, displayTransform,
+ args->downTime, args->eventTime, args->pointerCount,
+ args->pointerProperties, args->pointerCoords);
+
+ if(mPolicy->interceptMotionBeforeQueueing(&event, policyFlags)){
+ return;
+ }
+ /* 24.07.22 -- end */
+
bool needWake = false;
{ // acquire lock
mLock.lock();
if (shouldSendMotionToInputFilterLocked(args)) {
+/* 24.07.22 -- start */
+ mLock.unlock();
+/*
ui::Transform displayTransform;
if (const auto it = mDisplayInfos.find(args->displayId); it != mDisplayInfos.end()) {
displayTransform = it->second.transform;
}
mLock.unlock();
MotionEvent event;
event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
@@ -4035,7 +4057,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
args->xCursorPosition, args->yCursorPosition, displayTransform,
args->downTime, args->eventTime, args->pointerCount,
args->pointerProperties, args->pointerCoords);
-
+*/
+/* 24.07.22 -- end */
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
frameworks/native/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -88,6 +88,10 @@ public:
*/
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0;
+ /* 24.07.22 -- start */
+ virtual bool interceptMotionBeforeQueueing(const InputEvent* inputEvent, uint32_t policyFlags) = 0;
+ /* 24.07.22 -- end */
+
/* Intercepts a key event immediately before queueing it.
* The policy can use this method as an opportunity to perform power management functions
* and early event preprocessing such as updating policy flags.
添加调用接口
frameworks/base/core/java/android/hardware/input/IInputManager.aidl
@@ -36,6 +36,10 @@ import android.view.InputMonitor;
import android.view.PointerIcon;
import android.view.VerifiedInputEvent;
+/* 24.08.20 -- start */
+import android.hardware.input.IInputEventListener;
+/* 24.08.20 -- end */
+
/** @hide */
interface IInputManager {
// Gets input device information.
@@ -155,4 +159,9 @@ interface IInputManager {
void closeLightSession(int deviceId, in IBinder token);
void cancelCurrentTouch();
+
+ /* 24.06.27 -- start */
+ void registerInputEventListener(IInputEventListener listener);
+ void unregisterInputEventListener(IInputEventListener listener);
+ /* 24.06.27 -- end */
}
frameworks/base/core/java/android/hardware/input/InputManager.java
@@ -1108,6 +1108,29 @@ public final class InputManager {
}
}
+ /* 24.06.27 -- start */
+ /*
+ public interface Callback {
+ boolean onInputEvent(InputEvent event, int mode);
+ }*/
+
+ public void registerInputEventListener(IInputEventListener listener) {
+ try {
+ mIm.registerInputEventListener(listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ public void unregisterInputEventListener(IInputEventListener listener) {
+ try {
+ mIm.unregisterInputEventListener(listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+ /* 24.06.27 -- end */
+
/**
* Injects an input event into the event system, targeting windows owned by the provided uid.
*
编译
make update-api
make framework-minus-apex
app调用验证
...
import android.hardware.input.IInputEventListener;
import android.hardware.input.InputManager;
...
private InputEventListener mInputEventListener = new InputEventListener();
private InputManager mIm;
...
mIm = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
mIm.registerInputEventListener(mInputEventListener);
...
private final class InputEventListener extends IInputEventListener.Stub {
@Override
public boolean interceptMotionBeforeQueueing(InputEvent event,int mode) throws RemoteException {
Log.d(TAG,"interceptMotionBeforeQueueing:" + event.toString() + ",mode:" + mode + ",getSource:" + event.getSource());
if(event instanceof MotionEvent) {
MotionEvent motionEvent = (MotionEvent) event;
if(motionEvent.getSource() != InputDevice.SOURCE_MOUSE){
//不是鼠标事件
}
}
//返回true拦截
return false;
}
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags){
Log.e(TAG,"interceptKeyBeforeQueueing:" + event.toString());
//返回0 拦截
return 1;
}
}