软件平台: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...增量编译验证即可.