android 在frameworks添加监听、拦截触摸和按键的接口

在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;
        }
    }
修改 Android frameworks 中的 Java 代码后,需要进行编译,并将其 push 到设备中进行测试。下面是具体的步骤: 1. 编译 Android 源代码 在 Android 源代码根目录下执行以下命令: ``` $ source build/envsetup.sh $ lunch <target> $ make -j8 ``` 其中,`<target>` 表示你要编译的 Android 版本和设备类型,比如 `aosp_arm-eng`。 2. 编译 frameworks 模块 进入 frameworks 模块目录,执行以下命令: ``` $ cd frameworks/base $ mm ``` 如果只修改了某个子模块(比如 frameworks/base/core/java),可以只编译该子模块,例如: ``` $ cd frameworks/base/core/java $ mm ``` 3. 将编译后的 APK 推送到设备 执行以下命令将编译后的 APK 推送到设备中: ``` $ adb push out/target/product/<device>/system/framework/framework.jar /system/framework/ $ adb push out/target/product/<device>/system/framework/framework-res.apk /system/framework/ ``` 其中,`<device>` 表示你的设备类型。 4. 重启设备 执行以下命令重启设备: ``` $ adb reboot ``` 5. 测试修改结果 等待设备重启后,使用 adb shell 进入设备的 shell 界面,执行以下命令查看修改后的结果: ``` $ adb shell $ logcat -s YOUR_TAG ``` 其中,`YOUR_TAG` 表示你在代码中设置的 Log Tag。如果你修改了系统服务,可以使用以下命令查看服务状态: ``` $ adb shell dumpsys service YOUR_SERVICE_NAME ``` 其中,`YOUR_SERVICE_NAME` 表示你修改的系统服务名称。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值