自学内容网 自学内容网

Android 11添加电容笔电量监测需求

软件平台:Android11

硬件平台:QCS6125

    需求:PAD接入电容笔,该笔通过驱动上报坐标及当前电量等数据,即走系统的input通道,需要系统层监测到该硬件数据,这里主要展示电量,对用户显示提醒。

基本实现思路:通过在InputManager的本地层注册监听回调,实现监测的目的。

    直接上代码改动:

1、input的native层面改动frameworks/native:

diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 84838ec8a..7b900e758 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -102,7 +102,8 @@ NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t device
                                    const PointerCoords* pointerCoords, float xPrecision,
                                    float yPrecision, float xCursorPosition, float yCursorPosition,
                                    nsecs_t downTime,
-                                   const std::vector<TouchVideoFrame>& videoFrames)
+                                   const std::vector<TouchVideoFrame>& videoFrames,
+                                   uint32_t penBattery)
       : NotifyArgs(id, eventTime),
         deviceId(deviceId),
         source(source),
@@ -121,7 +122,8 @@ NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t device
         xCursorPosition(xCursorPosition),
         yCursorPosition(yCursorPosition),
         downTime(downTime),
-        videoFrames(videoFrames) {
+        videoFrames(videoFrames),
+        penBattery(penBattery) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
         this->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -147,7 +149,8 @@ NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other)
         xCursorPosition(other.xCursorPosition),
         yCursorPosition(other.yCursorPosition),
         downTime(other.downTime),
-        videoFrames(other.videoFrames) {
+        videoFrames(other.videoFrames),
+        penBattery(other.penBattery) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(other.pointerProperties[i]);
         pointerCoords[i].copyFrom(other.pointerCoords[i]);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fe016af01..f86178917 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3155,11 +3155,11 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
           "displayId=%" PRId32 ", policyFlags=0x%x, "
           "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
           "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
-          "yCursorPosition=%f, downTime=%" PRId64,
+          "yCursorPosition=%f, penBattery=%d, downTime=%" PRId64,
           args->id, args->eventTime, args->deviceId, args->source, args->displayId,
           args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
           args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
-          args->xCursorPosition, args->yCursorPosition, args->downTime);
+          args->xCursorPosition, args->yCursorPosition, args->penBattery, args->downTime);
     for (uint32_t i = 0; i < args->pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
               "x=%f, y=%f, pressure=%f, size=%f, "
@@ -3192,6 +3192,20 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
               std::to_string(t.duration().count()).c_str());
     }
 
+    if (args->action == AMOTION_EVENT_ACTION_DOWN) {
+        uint32_t penBattery = args->penBattery;
+        if (PEN_BATTERY_MIN <= penBattery && penBattery <= PEN_BATTERY_MAX) {
+            ALOGD("reportPenBattery # penBattery:%d", penBattery);
+
+            android::base::Timer timer;
+            mPolicy->reportPenBattery(args->displayId, args->eventTime, penBattery);
+            if (timer.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+                ALOGW("Excessive delay in reportPenBattery; took %s ms",
+                      std::to_string(timer.duration().count()).c_str());
+            }
+        }
+    }
+
     bool needWake;
     { // acquire lock
         mLock.lock();
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 667af9bbd..cb9b930f1 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -83,6 +83,9 @@ public:
     virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
                                                uint32_t& policyFlags) = 0;
 
+    /* 上报主动笔的电量 */
+    virtual void reportPenBattery(const int32_t displayId, nsecs_t when, uint32_t penBattery) {}
+
     /* Allows the policy a chance to intercept a key before dispatching. */
     virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
                                                   const KeyEvent* keyEvent,
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 8317b051e..c54830aa8 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -23,6 +23,14 @@
 #include <input/TouchVideoFrame.h>
 #include <utils/RefBase.h>
 
+// 主动笔电量值范围
+#define PEN_BATTERY_UNKNOWN 255
+#define PEN_BATTERY_MIN     0
+#define PEN_BATTERY_MAX     100
+
+// 主动笔电量值的 input-event-code
+#define ABS_PEN_BATT        0x1d
+
 namespace android {
 
 class InputListenerInterface;
@@ -121,6 +129,9 @@ struct NotifyMotionArgs : public NotifyArgs {
     nsecs_t downTime;
     std::vector<TouchVideoFrame> videoFrames;
 
+    // 主动笔电量值
+    uint32_t penBattery;
+
     inline NotifyMotionArgs() { }
 
     NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -130,7 +141,8 @@ struct NotifyMotionArgs : public NotifyArgs {
                      const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
                      float xPrecision, float yPrecision, float xCursorPosition,
                      float yCursorPosition, nsecs_t downTime,
-                     const std::vector<TouchVideoFrame>& videoFrames);
+                     const std::vector<TouchVideoFrame>& videoFrames,
+                     uint32_t penBattery = PEN_BATTERY_UNKNOWN);
 
     NotifyMotionArgs(const NotifyMotionArgs& other);
 
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index decbea4c3..2445fcf0f 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1407,6 +1407,13 @@ void TouchInputMapper::process(const RawEvent* rawEvent) {
     mCursorScrollAccumulator.process(rawEvent);
     mTouchButtonAccumulator.process(rawEvent);
 
+    if (rawEvent->type == EV_ABS && rawEvent->code == ABS_PEN_BATT) {
+        mPenBattery = rawEvent->value;
+        if (mPenBattery < PEN_BATTERY_MIN || mPenBattery > PEN_BATTERY_MAX) {
+            mPenBattery = PEN_BATTERY_UNKNOWN;
+        }
+    }
+
     if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
         sync(rawEvent->when);
     }
@@ -2498,7 +2505,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
                               policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                               buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                               1, &pointerProperties, &pointerCoords, 0, 0, x, y,
-                              mPointerGesture.downTime, /* videoFrames */ {});
+                              mPointerGesture.downTime, /* videoFrames */ {}, mPenBattery);
         getListener()->notifyMotion(&args);
     }
 
@@ -3412,7 +3419,6 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
 
     if (mPointerSimple.down && !down) {
         mPointerSimple.down = false;
-
         // Send up.
         NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
                               policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
@@ -3420,7 +3426,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
                               &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
                               xCursorPosition, yCursorPosition, mPointerSimple.downTime,
-                              /* videoFrames */ {});
+                              /* videoFrames */ {}, mPenBattery);
         getListener()->notifyMotion(&args);
     }
 
@@ -3434,7 +3440,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
                               &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
                               xCursorPosition, yCursorPosition, mPointerSimple.downTime,
-                              /* videoFrames */ {});
+                              /* videoFrames */ {}, mPenBattery);
         getListener()->notifyMotion(&args);
     }
 
@@ -3450,7 +3456,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
                                   &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {},
+                                  mPenBattery);
             getListener()->notifyMotion(&args);
         }
 
@@ -3461,7 +3468,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
                               &mPointerSimple.currentCoords, mOrientedXPrecision,
                               mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                              mPointerSimple.downTime, /* videoFrames */ {});
+                              mPointerSimple.downTime, /* videoFrames */ {}, mPenBattery);
         getListener()->notifyMotion(&args);
     }
 
@@ -3476,7 +3483,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
                                   &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {},
+                                  mPenBattery);
             getListener()->notifyMotion(&args);
         }
 
@@ -3487,7 +3495,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
                               &mPointerSimple.currentCoords, mOrientedXPrecision,
                               mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                              mPointerSimple.downTime, /* videoFrames */ {});
+                              mPointerSimple.downTime, /* videoFrames */ {}, mPenBattery);
         getListener()->notifyMotion(&args);
     }
 
@@ -3509,7 +3517,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
                               &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
                               xCursorPosition, yCursorPosition, mPointerSimple.downTime,
-                              /* videoFrames */ {});
+                              /* videoFrames */ {}, mPenBattery);
         getListener()->notifyMotion(&args);
     }
 
@@ -3577,11 +3585,12 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32
     std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
     std::for_each(frames.begin(), frames.end(),
                   [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
+
     NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
                           action, actionButton, flags, metaState, buttonState,
                           MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
                           pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
-                          downTime, std::move(frames));
+                          downTime, std::move(frames), mPenBattery);
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 1c2cc18f9..8bdfa513e 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -380,6 +380,9 @@ protected:
 
     std::vector<VirtualKey> mVirtualKeys;
 
+    // 主动笔电量值
+    int32_t mPenBattery = PEN_BATTERY_UNKNOWN;
+
     virtual void configureParameters();
     virtual void dumpParameters(std::string& dump);
     virtual void configureRawPointerAxes();
@@ -766,4 +769,4 @@ private:
 
 } // namespace android
 
-#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
\ No newline at end of file
+#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H

2、framework java部分改动frameworks/base:

diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e366edd8567..ea32451662f 100755
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -716,6 +716,9 @@
     <protected-broadcast android:name="com.android.systemui.action.START_MORE_SETTINGS" />
     <protected-broadcast android:name="com.android.systemui.demo" />
 
+    <!-- 主动笔电量通知 -->
+    <protected-broadcast android:name="com.android.server.policy.PEN_BATTERY_NOTIFY" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 115899a2a51..22b344de870 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1988,6 +1988,12 @@ public class InputManagerService extends IInputManager.Stub
                 displayId, whenNanos, policyFlags);
     }
 
+    // Native callback.
+    private int reportPenBatteryInteractive(int displayId, long whenNanos, int penBattery) {
+        return mWindowManagerCallbacks.reportPenBatteryInteractive(displayId, whenNanos,
+                penBattery);
+    }
+
     // Native callback.
     private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
         return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
@@ -2228,6 +2234,9 @@ public class InputManagerService extends IInputManager.Stub
         int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
                 int policyFlags);
 
+        /* 用户交互时上报主动笔的电量 */
+        int reportPenBatteryInteractive(int displayId, long whenNanos, int penBattery);
+
         public long interceptKeyBeforeDispatching(IBinder token,
                 KeyEvent event, int policyFlags);
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 05b178ce530..7a7e114896b 100755
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -226,6 +226,8 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+
 import android.yuanfudao.util.CommonUtils;
 
 /**
@@ -644,6 +646,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     private static final int MSG_RINGER_TOGGLE_CHORD = 26;
     private static final int MSG_RESET_ADB_ACTION = 100;
 
+    // 主动笔电量广播
+    private static final String ACTION_PEN_BATTERY_NOTIFY = "com.android.server.policy.PEN_BATTERY_NOTIFY";
+    private static final String PEN_BATTERY_LEVEL = "pen_battery_level";
+
+    // 主动笔电量值范围
+    private static final int PEN_BATTERY_UNKNOWN = 255;
+    private static final int PEN_BATTERY_MIN = 0;
+    private static final int PEN_BATTERY_MAX = 100;
+
+    // 主动笔电量值
+    private int mPenBattery = PEN_BATTERY_UNKNOWN;
+
+    // 主动笔电量广播,唤醒后首次需要发送;启动后首次也需要发送
+    private boolean mPenBatteryNeedNotify = true;
+
+    // 主动笔电量低电时需要发送广播
+    private final int[] mPenBatteryLow = { 10, 20 };
+
     private class PolicyHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
@@ -4269,6 +4289,51 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         return 0;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public int reportPenBatteryInteractive(int displayId, long whenNanos, int penBattery) {
+        Slog.d(TAG, "reportPenBatteryInteractive # penBattery:" + penBattery + ", mPenBattery:" + mPenBattery
+                + ", mPenBatteryNeedNotify:" + mPenBatteryNeedNotify);
+        // 唤醒后主动笔电量值低于20%时需要发送广播
+        boolean needNotify = mPenBatteryNeedNotify && mPenBattery <= mPenBatteryLow[1];
+        mPenBatteryNeedNotify = false;
+        if (PEN_BATTERY_MIN <= penBattery && penBattery <= PEN_BATTERY_MAX) {
+            if (mPenBattery != penBattery) {
+                // 主动笔电量值降低到阀值及一下时需要发送广播
+                needNotify = needNotify || isPenBatteryLowNotify(mPenBattery, penBattery);
+                mPenBattery = penBattery;
+            }
+
+            if (needNotify) {
+                notifyPenBattery(mPenBattery);
+            }
+        }
+        return 0;
+    }
+
+    /* 发送主动笔电量通知广播 */
+    private void notifyPenBattery(int penBattery) {
+        Slog.d(TAG, "notifyPenBattery # penBattery:" + penBattery + ", isScreenOn:" + isScreenOn());
+        if (isScreenOn()) {
+            final Intent intent = new Intent(ACTION_PEN_BATTERY_NOTIFY);
+            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+            intent.putExtra(PEN_BATTERY_LEVEL, penBattery);
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
+    }
+
+    /* 主动笔电量值降低到阀值及以下时需要发送广播 */
+    private boolean isPenBatteryLowNotify(int oldValue, int newValue) {
+        boolean needNotify = false;
+        for (int value : mPenBatteryLow) {
+            if (newValue <= value && value < oldValue) {
+                needNotify = true;
+                break;
+            }
+        }
+        return needNotify;
+    }
+
     private boolean shouldDispatchInputWhenNonInteractive(int displayId, int keyCode) {
         // Apply the default display policy to unknown displays as well.
         final boolean isDefaultDisplay = displayId == DEFAULT_DISPLAY
@@ -4560,6 +4625,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         if (mDisplayFoldController != null) {
             mDisplayFoldController.finishedWakingUp();
         }
+
+        mPenBatteryNeedNotify = true;
     }
 
     private void wakeUpFromPowerKey(long eventTime) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index cffeaf3f476..e4ef6c77cd8 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -986,6 +986,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
     int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
             int policyFlags);
 
+    /* 用户交互时上报主动笔的电量 */
+    int reportPenBatteryInteractive(int displayId, long whenNanos, int penBattery);
+
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
      *
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 9c4ac890fed..16966987011 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -326,6 +326,12 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
                 displayId, whenNanos, policyFlags);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public int reportPenBatteryInteractive(int displayId, long whenNanos, int penBattery) {
+        return mService.mPolicy.reportPenBatteryInteractive(displayId, whenNanos, penBattery);
+    }
+
     /**
      * Provides an opportunity for the window manager policy to process a key before
      * ordinary dispatch.
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 30050547049..91e6a4324c5 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -93,6 +93,7 @@ static struct {
     jmethodID filterInputEvent;
     jmethodID interceptKeyBeforeQueueing;
     jmethodID interceptMotionBeforeQueueingNonInteractive;
+    jmethodID reportPenBatteryInteractive;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID dispatchUnhandledKey;
     jmethodID checkInjectEventsPermission;
@@ -250,6 +251,8 @@ public:
                                             uint32_t& policyFlags) override;
     virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
                                                uint32_t& policyFlags) override;
+    virtual void reportPenBattery(const int32_t displayId, nsecs_t when,
+                                  uint32_t penBattery) override;
     virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
                                                   const KeyEvent* keyEvent,
                                                   uint32_t policyFlags) override;
@@ -1057,6 +1060,21 @@ void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId,
     }
 }
 
+void NativeInputManager::reportPenBattery(const int32_t displayId, nsecs_t when,
+                                          uint32_t penBattery) {
+    ATRACE_CALL();
+    // bool interactive = mInteractive.load();
+    // if (interactive) {
+        JNIEnv* env = jniEnv();
+        jint wmActions =
+                env->CallIntMethod(mServiceObj, gServiceClassInfo.reportPenBatteryInteractive,
+                                   displayId, when, penBattery);
+        if (checkAndClearExceptionFromCallback(env, "reportPenBatteryInteractive")) {
+            wmActions = 0;
+        }
+    // }
+}
+
 void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
         uint32_t& policyFlags) {
     if (wmActions & WM_ACTION_PASS_TO_USER) {
@@ -1866,6 +1884,9 @@ int register_android_server_InputManager(JNIEnv* env) {
     GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive, clazz,
             "interceptMotionBeforeQueueingNonInteractive", "(IJI)I");
 
+    GET_METHOD_ID(gServiceClassInfo.reportPenBatteryInteractive, clazz,
+                  "reportPenBatteryInteractive", "(IJI)I");
+
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
             "(Landroid/os/IBinder;Landroid/view/KeyEvent;I)J");

3、SystemUI展示电量:

diff --git a/res/layout/pen_battery_notify_dialog_layout.xml b/res/layout/pen_battery_notify_dialog_layout.xml
new file mode 100755
index 0000000..80150c5
--- /dev/null
+++ b/res/layout/pen_battery_notify_dialog_layout.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/pen_battery"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:padding="24dp"
+    android:background="@drawable/custom_power_dialog_bg"
+    android:gravity="center_vertical"
+    android:focusable="true"
+    android:clickable="true"
+    android:orientation="horizontal">
+    <!-- <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:focusableInTouchMode="false"
+        android:src="@drawable/battery_black_splash_icon"
+    /> -->
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:focusableInTouchMode="false"
+        android:textColor="@color/black"
+        android:textSize="24sp"
+        android:text="AI手写笔电量:" />
+
+
+    <!-- <ImageView
+        android:id="@+id/battery_level_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="20dp"
+        android:focusable="false"
+        android:clickable="false"
+        android:focusableInTouchMode="false"
+        android:textColor="@color/black"
+        android:src="@drawable/battery_black_splash_icon"
+    /> -->
+
+    <!-- 显示主动笔电量 -->
+    <TextView
+        android:id="@+id/battery_level_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:focusableInTouchMode="false"
+        android:textColor="@color/black"
+        android:textSize="24sp" />
+</LinearLayout>
diff --git a/src/com/android/systemui/power/PenBatteryNotifyDialog.java b/src/com/android/systemui/power/PenBatteryNotifyDialog.java
new file mode 100755
index 0000000..d677c59
--- /dev/null
+++ b/src/com/android/systemui/power/PenBatteryNotifyDialog.java
@@ -0,0 +1,121 @@
+package com.android.systemui.power;^M
+^M
+import android.content.Context;^M
+import android.graphics.Color;^M
+import android.graphics.drawable.ColorDrawable;^M
+import android.os.Bundle;^M
+import android.util.Slog;^M
+import android.view.GestureDetector;^M
+import android.view.Gravity;^M
+import android.view.MotionEvent;^M
+import android.view.View;^M
+import android.view.Window;^M
+import android.view.WindowManager;^M
+import android.widget.ImageView;^M
+import android.widget.TextView;^M
+^M
+import androidx.annotation.NonNull;^M
+^M
+import com.android.systemui.R;^M
+import com.android.systemui.statusbar.phone.SystemUIDialog;^M
+^M
+public class PenBatteryNotifyDialog extends SystemUIDialog {^M
+    private static final String TAG = "PenBatteryNotifyDialog";^M
+    // static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);^M
+    static final boolean DEBUG = true;^M
+    private static final int MOVE_MIN = 50;^M
+^M
+    private View mRootView;^M
+    private TextView mBatteryLevelView;^M
+    private ImageView mBatteryIcon;^M
+    private GestureDetector mGestureDetector;^M
+    private int mBatteryLevel = 0;^M
+^M
+    public PenBatteryNotifyDialog(@NonNull Context context) {^M
+        super(context);^M
+    }^M
+^M
+    public PenBatteryNotifyDialog(@NonNull Context context, int themeResId) {^M
+        super(context, themeResId);^M
+    }^M
+^M
+    @Override^M
+    protected void onCreate(Bundle savedInstanceState) {^M
+        super.onCreate(savedInstanceState);^M
+        initDialogStyle();^M
+        setContentView(R.layout.pen_battery_notify_dialog_layout);^M
+        initView();^M
+    }^M
+^M
+    private void initView() {^M
+        // 监听上划手势,上划关闭弹窗^M
+        mGestureDetector =^M
+                new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {^M
+                    @Override^M
+                    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,^M
+                            float velocityY) {^M
+                        if (DEBUG) {^M
+                            Slog.d(TAG, "onFling() e1:" + e1 + ", e2:" + e2 + ", velocityX:"^M
+                                    + velocityX + ", velocityY:" + velocityY);^M
+                        }^M
+^M
+                        if (isShowing() && e1.getY() - e2.getY() > MOVE_MIN^M
+                                && Math.abs(velocityY) > MOVE_MIN) {^M
+                            Slog.i(TAG, "onFling() dialog dismiss!");^M
+                            dismiss();^M
+                            return true;^M
+                        }^M
+                        return false;^M
+                    }^M
+                });^M
+^M
+        mRootView = findViewById(R.id.pen_battery);^M
+        mRootView.setOnTouchListener((view, event) -> {^M
+            if (DEBUG) {^M
+                Slog.d(TAG, "onTouchEvent() event:" + event);^M
+            }^M
+            return mGestureDetector.onTouchEvent(event);^M
+        });^M
+^M
+        // mBatteryIcon = (ImageView) findViewById(R.id.battery_level_icon);^M
+        mBatteryLevelView = (TextView) findViewById(R.id.battery_level_text);^M
+        updatePenBatteryLevel();^M
+    }^M
+^M
+    public void setPenBatteryLevel(int level) {^M
+        mBatteryLevel = level;^M
+        updatePenBatteryLevel();^M
+    }^M
+^M
+    private void updatePenBatteryLevel() {^M
+        if (mBatteryLevelView != null) {^M
+            mBatteryLevelView.setText(mBatteryLevel + "%");^M
+        }^M
+    }^M
+^M
+    private void initDialogStyle() {^M
+        setCanceledOnTouchOutside(false);^M
+^M
+        Window window = getWindow();^M
+        // 设置弹窗背景透明^M
+        // window.setBackgroundDrawableResource(android.R.color.transparent);^M
+        window.setDimAmount(0.0f);^M
+        // 设置背景颜色为透明,主要是去掉四周圆角^M
+        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));^M
+        // 设置点击dialog外面,dialog会消失^M
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);^M
+^M
+        WindowManager.LayoutParams lp = window.getAttributes();^M
+        // lp.format = PixelFormat.TRANSLUCENT;^M
+        // lp.windowAnimations = 0;^M
+        lp.dimAmount = 0.0f;^M
+        // 设置显示位置:屏幕顶部居中显示^M
+        lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;^M
+        // lp.x = 40;^M
+        lp.y = 130;^M
+        // 设置大小^M
+        // lp.width = 300;^M
+        // lp.height = 300;^M
+        window.setAttributes(lp);^M
+    }^M
+}^M
diff --git a/src/com/android/systemui/power/PowerUI.java b/src/com/android/systemui/power/PowerUI.java
index 710de41..6dad1f6 100755
--- a/src/com/android/systemui/power/PowerUI.java
+++ b/src/com/android/systemui/power/PowerUI.java
@@ -248,6 +248,25 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
         public LowBatteryAutoShutDownDialog lowBatteryAutoShutDownDialog;
         private static final int BATTERY_LEVEL_NEED_SHUT_DOWN = 1 ;
 
+        // 主动笔电量广播
+        private static final String ACTION_PEN_BATTERY_NOTIFY = "com.android.server.policy.PEN_BATTERY_NOTIFY";
+        private static final String PEN_BATTERY_LEVEL = "pen_battery_level";
+
+        // 主动笔电量值范围
+        private static final int PEN_BATTERY_UNKNOWN = 255;
+        private static final int PEN_BATTERY_MIN = 0;
+        private static final int PEN_BATTERY_MAX = 100;
+
+        // 主动笔电量提示弹窗
+        private PenBatteryNotifyDialog mPenBatteryNotifyDialog;
+        private Runnable mPenBatteryDialogDissmisRunnable = () -> {
+            if (mPenBatteryNotifyDialog != null && mPenBatteryNotifyDialog.isShowing()) {
+                Log.i(TAG, "mPenBatteryNotifyDialog time out and dismiss!");
+                mPenBatteryNotifyDialog.dismiss();
+            }
+        };
+
+
         public void init() {
             // Register for Intent broadcasts for...
             IntentFilter filter = new IntentFilter();
@@ -261,6 +280,8 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
              */
             filter.addAction(Intent.ACTION_SCREEN_ON);
             filter.addAction(Intent.ACTION_USER_SWITCHED);
+            // 主动笔电量广播
+            filter.addAction(ACTION_PEN_BATTERY_NOTIFY);
             mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
             // Force get initial values. Relying on Sticky behavior until API for getting info.
             if (!mHasReceivedBattery) {
@@ -397,11 +418,41 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
 
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mWarnings.userSwitched();
+            } else if (ACTION_PEN_BATTERY_NOTIFY.equals(action)) {
+                // 收到广播显示主动笔电量提示弹窗
+                final int penBattery = intent.getIntExtra(PEN_BATTERY_LEVEL, PEN_BATTERY_UNKNOWN);
+                Log.i(TAG, "penBattery:" + penBattery);
+                if (PEN_BATTERY_MIN <= penBattery && penBattery <= PEN_BATTERY_MAX) {
+                    showPenBatteryNotifyDialog(context, penBattery);
+                }
             } else {
                 Slog.w(TAG, "unknown intent: " + intent);
             }
         }
 
+        /*
+         * 显示主动笔电量提示弹窗,如果弹窗正在显示则仅更新电量数值
+         *
+         * @param context Context
+         *
+         * @param penBatteryLevel 主动笔电量
+         */
+        private void showPenBatteryNotifyDialog(Context context, int penBatteryLevel) {
+            Log.i(TAG, "showPenBatteryNotifyDialog() penBatteryLevel:" + penBatteryLevel);
+            if (mPenBatteryNotifyDialog == null) {
+                mPenBatteryNotifyDialog = new PenBatteryNotifyDialog(context);
+                mPenBatteryNotifyDialog.setShowForAllUsers(true);
+            }
+            SystemUIDialog.setWindowOnTop(mPenBatteryNotifyDialog);
+            mPenBatteryNotifyDialog.setPenBatteryLevel(penBatteryLevel);
+            if (!mPenBatteryNotifyDialog.isShowing()) {
+                mPenBatteryNotifyDialog.show();
+            }
+            // 3s 后自动关闭
+            mHandler.removeCallbacks(mPenBatteryDialogDissmisRunnable);
+            mHandler.postDelayed(mPenBatteryDialogDissmisRunnable, 3000);
+        }
+
         /**
          * handle Battery Status Changed Situation.
          * @param context Context

Mark it...增量编译验证即可.


原文地址:https://blog.csdn.net/DKBDKBDKB/article/details/144685827

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!