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 deviceconst 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 devicexCursorPosition(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 lockmLock.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 policyFlagpolicyFlags, 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, uint32std::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.StubdisplayId, 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.Stubint 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 {@Overridepublic 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.WindowManagerCaldisplayId, 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...增量编译验证即可.
相关文章:
Android 11添加电容笔电量监测需求
软件平台:Android11 硬件平台:QCS6125 需求:PAD接入电容笔,该笔通过驱动上报坐标及当前电量等数据,即走系统的input通道,需要系统层监测到该硬件数据,这里主要展示电量,对用户显示提…...
迈向AGI——大模型创新体验嘉年华邀请函
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 深度对话,思想碰撞 大模型创新体验嘉年华诚邀您与我们共同见证 智见未来,只等你来 往期精彩文章推荐 关于AI TIME AI TIME源起于2019年,旨在发扬科学思辨精神,…...
VSCode 性能优化指南:提高编码效率,减少资源占用
Visual Studio Code(简称VSCode)是一款广受欢迎的代码编辑器,以其强大的功能和丰富的插件生态系统著称。然而,随着项目规模的扩大和插件数量的增加,VSCode 的性能可能会受到影响。本文将介绍一系列优化措施,…...
如何获取 ABAP 内表中的重复项
要识别 ABAP 内表中的重复项,可以结合使用排序和循环。下面的示例展示了如何查找内部表中的重复条目: DATA: BEGIN OF itab OCCURS 0,field1 TYPE i,field2 TYPE c LENGTH 10,END OF itab,wa LIKE LINE OF itab.* Add sample data to internal table it…...
android 登录界面编写
1、登录页面实现内容 1.实现使用两个EditText输入框输入用户名和密码。 2.使用CheckBox控件记住密码功能。 3.登录时候,验证用户名和密码是否为空。 4.当前CheckBox控件记住密码勾上时,使用SharedPreferences存储用户名和密码。 5.登录时候使用Prog…...
3D-resnet 50 医学3D图像二分类python代码
离上次发布3D-resnet代码时隔两年,最近让AI推荐3D-resnet的文章给我,AI推荐了三篇 其中两篇是我两年前发的,另一篇在这里Resnet3D预训练网络...... 于是决定更新之前代码,供诸位参考1. 可以用cpu或gpu(推荐8G以上&…...
android sqlite 数据库简单封装示例(java)
sqlite 数据库简单封装示例,使用记事本数据库表进行示例。 首先继承SQLiteOpenHelper 使用sql语句进行创建一张表。 public class noteDBHelper extends SQLiteOpenHelper {public noteDBHelper(Context context, String name, SQLiteDatabase.CursorFactory fact…...
项目练习:若依-前端项目的目录结构介绍
文章目录 一、目录截图二、目录讲解 一、目录截图 二、目录讲解 1、首先,我们可以看到,这个VUE项目,只有一个App.vue,所以,它是一个单页面系统。 这个App.vue是根组件,root组件。 2、public目录 在Vue 3.…...
Android 之 List 简述
一、简单创建方式 Android 开发中,列表有很多种类,如ArrayList、LinkedList、List、MutableList等,创建列表的方式如下所示: fun listDemo() {// 使用 listOf 创建不可变的空列表val list listOf<Int>()val list1 listOf…...
CV(6)-SIFT和Hash
前言 仅记录学习过程,有问题欢迎讨论 SIFT:尺度不变特征变换: SIFT提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置、尺度、方向信息。SIFT的应用范围包括物体辨别、机器人地图感知与导航、影像拼接、3D模型建立、手势…...
javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.13.13 not verified:
javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.13.13 not verified: 前言: 之前需求推送数据是采用http:192.168.13.13:8000 后面业务需求修改为 https:192.168.13.13:443 修改后推送数据到第三方报以下异常, https://192.168.13.13:443…...
用Unity做没有热更需求的单机游戏是否有必要使用AssetBundle?
在使用Unity开发没有热更需求的单机游戏时,是否使用AssetBundle(AB包)是一个值得探讨的问题。以下是对此问题的详细分析: 一、AssetBundle的概述 AssetBundle是Unity中用于存储和加载游戏资源的打包文件,可以包含各种…...
WebRTC Simulcast 大小流介绍与优化实践
Simulcast 是 WebRTC 中的一种标准化技术 ,简称大小流。通过 Simulcast,客户端可以同时发送同一视频的多个版本。每个版本都以不同的分辨率和帧率独立编码,带宽较多的拉流端可以接收较高质量的视频流,带宽有限的拉流端则可以接收较…...
软件测试之测试用例
文章目录 测试用例测试用例的编写总结 测试用例 测试用例:描述测试点执行的文档(测试输入、执行条件、预期结果等) 作用 1.测试点能被精准执行 2.便于团队合作测试用例核心内容 用例编号、用例标题、所属模块、优先级、前置条件、测试步骤、测试数据、预期结果 测试用例的编写…...
Redis--通用命令学习
目录 一、引言 二、基础命令 1.set 2.get 3.keys 3.1 keys ? 3.2 keys * 3.3 keys [abe] 3.4 keys [^] 3.5 keys [a-b] 4.exists 5.delete 6.expire 7.ttl 8.type 三、Redis中的过期策略(面试题) 1.惰性删除 2.定期删除 …...
自动控制系统综合与LabVIEW实现
自动控制系统综合是为了优化系统性能,确保其可靠性、稳定性和灵活性。常用方法包括动态性能优化、稳态误差分析、鲁棒性设计等。结合LabVIEW,可以通过图形化编程、高效数据采集与处理来实现系统综合。本文将阐述具体方法,并结合硬件选型提供实…...
一篇文章学会HTML
目录 页面结构 网页基本标签 图像标签 超链接标签 文本链接 图像链接 锚链接 功能链接 列表 有序列表 无序列表 自定义列表 表格 跨列/跨行 表头 媒体元素 视频 音频 网站的嵌套 表单 表单元素 文本框 单选框 多选框 按钮 下拉框 文本域和文件域 表…...
48页PPT|2024智慧仓储解决方案解读
本文概述了智慧物流仓储建设方案的行业洞察、业务蓝图及建设方案。首先,从政策层面分析了2012年至2020年间国家发布的促进仓储业、物流业转型升级的政策,这些政策强调了自动化、标准化、信息化水平的提升,以及智能化立体仓库的建设࿰…...
React Props 完整使用指南
React Props 完整使用指南 1. 类组件中的 Props 1.1 基本使用 // 父组件 class ParentComponent extends React.Component {render() {return (<ChildComponent name"John"age{25}isStudent{true}hobbies{[reading, swimming]}/>);} }// 子组件 class Child…...
金融数据可视化实现
一、设计题目 金融数据可视化 二、设计目的 使学生掌握用Pandas第三方库数据计算、数据分析的知识与能力。Pandas是专门用于数据分析的库,其提供的read_excel()方法可以方便的读取xlsx格式的文件中的数据到Pandas中的DataFrame中。 DataFrame.plot(kindline)&am…...
逆袭之路(6)——解析数据世界的灵动基石——变量
困厄铸剑心,逆袭展锋芒。 寒苦凝壮志,腾跃绘华章。 我要逆袭。 目录 一、引言 二、变量的定义 三、变量的性质 (一)可变性 (二)有界性 (三)关联性 四、变量的类型 ÿ…...
【云原生】kubeadm搭建的kubernetes1.28集群上自建ingress-nginx服务
1、查询兼容性 先确认下kubernetes版本与ingress-nginx版本兼容性 Ingress-NGINX 版本支持的 k8s 版本Alpine 版本Nginx 版本Helm Chart 版本v1.12.0-beta.01.31, 1.30, 1.29, 1.283.20.31.25.54.12.0-beta.0v1.11.31.30, 1.29, 1.28, 1.27, 1.263.20.31.25.54.11.3v1.11.21.3…...
分布式协同 - 分布式事务_TCC解决方案
文章目录 导图Pre流程图2PC VS 3PC VS TCC2PC(Two-Phase Commit,二阶段提交)3PC(Three-Phase Commit,三阶段提交)TCC(Try-Confirm-Cancel)2PC、3PC与TCC的区别2PC、3PC与TCC的联系 导…...
两分钟解决:vscode卡在设置SSH主机,VS Code-正在本地初始化VSCode服务器
问题原因 remote-ssh还是有一些bug的,在跟新之后可能会一直加载初始化SSH主机解决方案 1.打开终端2.登录链接vscode的账号,到家目录下3.找到 .vscode-server文件,删掉这个文件4.重启 vscode 就没问题了...
SpringBoot3整合FastJSON2如何配置configureMessageConverters
在 Spring Boot 3 中整合 FastJSON 2 主要涉及到以下几个步骤,包括添加依赖、配置 FastJSON 作为 JSON 处理器等。下面是详细的步骤: 1. 添加依赖 首先,你需要在你的 pom.xml 文件中添加 FastJSON 2 的依赖。以下是 Maven 依赖的示例&#…...
数据库安全-redisCouchdb
1.redis未授权访问 默认端口:6379 1.1 Redis沙盒逃逸漏洞RCE-CVE-2022-0543 介绍:Redis 是一套开源的使用 ANSI C编写、支持网络、可基于内存亦可持久化的日志型、键值存储数据库,并提供多种语言的API。Redis 如果在没有开启认证的情况下,…...
java如何使用poi-tl在word模板里渲染多张图片
1、poi-tl官网地址 http://deepoove.com/poi-tl/ 2、引入poi-tl的依赖 <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version></dependency>3、定义word模板 释义…...
ASP.NET |日常开发中常见问题归纳讲解
ASP.NET |日常开发中常见问题归纳讲解 前言一、性能问题1.1 数据库访问性能1.2 视图状态(在ASP.NET Web Forms 中) 二、安全问题2.1 SQL 注入2.2 跨站脚本攻击(XSS) 三、状态管理问题3.1 会话状态(Session …...
Jenkins安全部署规范及安全基线
Jenkins安全部署规范及安全基线 进入安全设置界面启用安全Disable remember me访问控制——安全域(Security Realm)servlet容器代理(Delegate to servlet container)Jenkins专有用户数据库(Jenkins’ own user databas…...
stm32定时器输出比较----驱动步进电机
定时器输出比较理论 OC(Output Compare)输出比较输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形每个高级定时器和通用定时器都拥有4个输出比较通道高级定时器的前3个通道额外拥有死区生成和互补输出…...
文本文件和二进制文件
1.为什么使用文件 使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。 2. 什么是文件 磁盘上的文件是文件。 但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)…...
Linux 常见用例汇总
注:本文为 Linux 常见用例文章合辑。 部分内容已过时,未更新整理。 检查 Linux 上的 glibc 版本 译者:joeren | 2014-11-27 21:33 问:检查 Linux 系统上的 GNU C 库(glibc)的版本? GNU C 库&…...
R9000P键盘失灵解决办法
问题描述 突然,就是很突然,我买的R9000P 2024不到三个月,键盘突然都不能用了,是所有键盘按键都无效的那种。(可以使用外接键盘) 解决办法 我本科室友说的好哈,全坏全没坏。 (该解…...
Windows、CentOS环境下搭建自己的版本管理资料库:GitBlit
可以搭建属于公司内部或者个人的Git服务器,方便程序代码及文档版本管理。 官网:http://www.gitblit.com/ Windows环境下安装 提前已经安装好了JDK。 官网下载Windows版的GitBlit。 将zip包解压到自己想要放置的文件夹下。 建立版本库路径,…...
《Web 应用项目开发:从构思到上线的全过程》
目录 一、引言 二、项目启动与需求分析 三、设计阶段 四、技术选型 五、开发阶段 六、测试阶段 七、部署与上线 八、维护与更新 九、总结 一、引言 在数字化浪潮席卷全球的当下,Web 应用如繁星般在互联网的苍穹中闪烁,它们形态各异,…...
ctf相关总结
CTF比赛定义: CTF(Capture The Flag)是一种信息安全竞赛形式,参赛队伍通过破解题目获取flag来得分。 比赛流程: 参赛队伍在题目平台上登录,选择题目进行解答,提交flag后由系统自动评分。 三…...
v3s点RGB屏 40pin 800x480,不一样的点屏,不通过chosen。
一、背景、目的、简介。 一般来说,通过uboot将屏幕参数传给kernel,是通过修改设备树。 uboot和kernel都需要屏幕点亮。uboot侧重于显示一张图片。而kernel则多是动画。 在这里,我先是找到了一个裸机点屏的代码。将其编译成静态库后&#x…...
学习笔记(prism--视频【WPF-prism核心教程】)--待更新
《一》框架介绍 prism是一个用于WPF…和winUI中构建的松散耦合,可维护和可测试的应用程序框架。帮助WPF开发人员以简化编写,维护和扩展来设计应用程序。 优点:遵循特定的约定,可自动将view/ViewModel建立DataContext的关系&#…...
从AI换脸到篡改图像,合合信息如何提升视觉内容安全?
本文目录 引言一、AI“真假之战”下的发展现状与考验挑战1.1 视觉内容安全现状与技术分类1.2视觉内容安全企业1.3视觉内容安全领域挑战 二、开山之石:引领视觉内容安全的创新之路2.1合合内容安全系统2.2发起编制相关技术规范2.3参与篡改检测挑战赛 三、视觉内容安全…...
12.12【java exp4】react table全局搜索tailwindcss 布局 (Layout) css美化 3. (rowId: number
react table 创建一个下拉菜单,允许用户选择要搜索的列。创建一个输入框,用于输入搜索关键词。根据用户的选择,动态地应用过滤器到指定的列 全局搜索 import React from react; import { useTable, useFilters, useGlobalFilter, useSortBy…...
‘pnpm’ 不是内部或外部命令,也不是可运行的程序或批处理文件。
‘pnpm’ 不是内部或外部命令,也不是可运行的程序或批处理文件。 1.情况: npm -v 和 node -v的都正常就是 pnpm-v 无效 检查环境变量也没看出问题 2.分析 没有正确添加环境变量 3.解决 找到npm的全局安装目录 npm list -g --depth 0这里出现了npm的全局安装…...
频繁拿下定点,华玉高性能中间件迈入商业化新阶段
伴随着智能驾驶渗透率的快速增长,中国基础软件市场开始进入黄金窗口期。 近日,华玉通软(下称“华玉”)正式获得某国内头部轨道交通产业集团的智能化中间件平台定点项目。这将是华玉在基础软件领域深耕和商业化发展过程中的又一重…...
装饰者模式
代码详解:【设计模式】Java 设计模式之装饰者模式(Decorator)_java 装饰者模式-CSDN博客 // 抽象构件角色 public interface Component {void operation(); }// 具体构件角色 public class ConcreteComponent implements Component {Override…...
【河南新标】豫财预〔2024〕105号-《关于省级政务信息化建设项目支出预算标准的规定》-费用标准解读系列29
2024年12月3日,河南省财政厅发布了《关于省级政务信息化建设项目支出预算标准的规定》豫财预〔2024〕105号。《关于省级政务信息化建设项目支出预算标准的规定 (试行)》(豫财预 〔2020〕81号)同时废止。新的豫财预〔20…...
Android 蓝牙开发-传输数据
概述 传统蓝牙是通过建立REFCCOM sockect来进行通信的,类似于socket通信,一台设备需要开放服务器套接字并处于listen状态,而另一台设备使用服务器的MAC地址发起连接。连接建立后,服务器和客户端就都通过对BluetoothSocket进行读写…...
使用VSCode Debugger 调试 React项目
一般我们调试代码时,用的最多的应该就是console.log方式了,还有的是使用Chrome DevTools 通过在对应的 sourcemap代码位置打断点进行调试,除了上面两种方式外还有一种更好用的调试方式: VSCode Debugger。 VSCode Debugger可以直…...
ArcGIS Pro 3.4新功能3:空间统计新特性,基于森林和增强分类与回归,过滤空间自相关
目录 应用 1:它是相关性还是托布勒第一定律? 应用 2:将空间带入非空间模型 结论 在 ArcGIS Pro 3.4 中,我们在新的空间组件实用程序(Moran 特征向量)工具集中发布了一个新工具 - 从字段过滤空间自相关。…...
Flink SQL Cookbook on Zeppelin 部署使用
简介:对于初学者来说,学习 Flink 可能不是一件容易的事情。看文档是一种学习,更重要的是实践起来。但对于一个初学者来说要把一个 Flink SQL 跑起来还真不容易,要搭各种环境,真心累。很幸运的是,Flink 生态…...
用二进制方式向文件读写一组数据
【例10.4】从键盘输入10个学生的有关数据,然后把它们转存到磁盘文件上去。 #include<stdio.h> struct Student{char name[20];int number;int age; }; int main(){int i;struct Student stu;FILE *fp;fp fopen("1.txt","wb");if(fp N…...
WebChat——一个开源的聊天应用
Web Chat 是开源的聊天系统,支持一键免费部署私人Chat网页的应用程序。 开源地址:https://github.com/loks666/webchat 目录树 TOC ??? 开始使用 & 交流?? 开箱即用 [这里是代码001] 使用 Docker 部署[这里是代码002] 使用 Docker-compose …...