-
Notifications
You must be signed in to change notification settings - Fork 335
feat: Android Native Controller #933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Reviewer's Guide添加一个原生 Android 控制单元(controller)实现,它基于 Android 控制单元共享库和 Kotlin 无障碍/MediaProjection 桥接;将其接入框架 API/CLI/类型系统,并更新构建/测试工作流以构建和打包 Android 工件。 创建和使用 Android 控制单元的时序图sequenceDiagram
actor User
participant Cli as MaaPiCli_Runner
participant Framework as MaaAndroidControllerCreate
participant LibHolder as AndroidControlUnitLibraryHolder
participant So as MaaAndroidControlUnit_so
participant CU as AndroidControlUnitMgr
participant JVM as JVM_ART
participant Bridge as NativeBridge
participant AccSvc as MaaAccessibilityService
User->>Cli: run(param with AndroidParam)
Cli->>Framework: MaaAndroidControllerCreate(screencap_methods, input_methods)
activate Framework
Framework->>LibHolder: create_control_unit(screencap_methods, input_methods)
activate LibHolder
LibHolder->>So: MaaAndroidControlUnitCreate(screencap_methods, input_methods)
activate So
So->>So: new AndroidControlUnitMgr
So-->>LibHolder: AndroidControlUnitHandle
deactivate So
LibHolder-->>Framework: shared_ptr AndroidControlUnitAPI
deactivate LibHolder
Framework->>Framework: new ControllerAgent(control_unit)
Framework-->>Cli: MaaController*
deactivate Framework
Note over Cli,Cli: Later, during controller initialization
Cli->>CU: connect()
activate CU
CU->>JVM: ensure_env()
CU->>Bridge: init(screencap_methods, input_methods)
CU->>Bridge: connect()
activate Bridge
Bridge->>Bridge: verify accessibility/media_projection availability
Bridge-->>CU: true/false
deactivate Bridge
CU-->>Cli: connect result
deactivate CU
Note over CU,Bridge: During operations (example: screencap)
Cli->>CU: screencap(image)
activate CU
CU->>Bridge: screencap()
activate Bridge
alt MediaProjection enabled and available
Bridge->>Bridge: mediaProjectionHolder.capture()
else Accessibility screenshot fallback
Bridge->>AccSvc: screencap()
activate AccSvc
AccSvc-->>Bridge: Bitmap
deactivate AccSvc
end
Bridge-->>CU: Bitmap
deactivate Bridge
CU-->>Cli: fill cv::Mat from Bitmap
deactivate CU
新增 Android 控制单元与 Kotlin 桥接的类图classDiagram
direction LR
class ControlUnitAPI {
<<abstract>>
+connect() bool
+request_uuid(uuid string) bool
+get_features() MaaControllerFeature
+start_app(intent string) bool
+stop_app(intent string) bool
+screencap(image cv_Mat) bool
+click(x int, y int) bool
+swipe(x1 int, y1 int, x2 int, y2 int, duration int) bool
+touch_down(contact int, x int, y int, pressure int) bool
+touch_move(contact int, x int, y int, pressure int) bool
+touch_up(contact int) bool
+click_key(key int) bool
+input_text(text string) bool
+key_down(key int) bool
+key_up(key int) bool
+scroll(dx int, dy int) bool
}
class AndroidControlUnitAPI {
<<abstract>>
}
class AndroidControlUnitMgr {
-screencap_methods_ MaaAndroidScreencapMethod
-input_methods_ MaaAndroidInputMethod
-vm_ JavaVM*
-bridge_cls_ jclass
+AndroidControlUnitMgr(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod)
+connect() bool
+request_uuid(uuid string) bool
+get_features() MaaControllerFeature
+start_app(intent string) bool
+stop_app(intent string) bool
+screencap(image cv_Mat) bool
+click(x int, y int) bool
+swipe(x1 int, y1 int, x2 int, y2 int, duration int) bool
+touch_down(contact int, x int, y int, pressure int) bool
+touch_move(contact int, x int, y int, pressure int) bool
+touch_up(contact int) bool
+click_key(key int) bool
+input_text(text string) bool
+key_down(key int) bool
+key_up(key int) bool
+scroll(dx int, dy int) bool
-ensure_env() JNIEnv*
-bridge_class() jclass
-call_bool(name char*, sig char*, caller Callable) bool
}
class AndroidControlUnitLibraryHolder {
+create_control_unit(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod) shared_ptr~AndroidControlUnitAPI~
-libname_ filesystem_path
-version_func_name_ string
-create_func_name_ string
-destroy_func_name_ string
}
class MaaAndroidControlUnit_API {
+MaaAndroidControlUnitGetVersion() const_char_ptr
+MaaAndroidControlUnitCreate(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod) MaaAndroidControlUnitHandle
+MaaAndroidControlUnitDestroy(handle MaaAndroidControlUnitHandle) void
}
class MaaController {
}
class ControllerAgent {
+ControllerAgent(control_unit shared_ptr~ControlUnitAPI~)
}
class MaaFramework_API {
+MaaAndroidControllerCreate(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod) MaaController*
}
class RuntimeParam {
+controller_param variant
}
class AndroidParam {
+screencap MaaAndroidScreencapMethod
+input MaaAndroidInputMethod
}
class Runner {
+run(param RuntimeParam) bool
}
class NativeBridge {
<<object>>
+SCREENCAP_METHOD_NONE long
+SCREENCAP_METHOD_ACCESSIBILITY long
+SCREENCAP_METHOD_MEDIA_PROJECTION long
+INPUT_METHOD_NONE long
+INPUT_METHOD_ACCESSIBILITY long
-accessibilityService MaaAccessibilityService
-mediaProjectionHolder MediaProjectionHolder
-screencapMethods long
-inputMethods long
+attachAccessibilityService(service MaaAccessibilityService) void
+detachAccessibilityService(service MaaAccessibilityService) void
+attachMediaProjection(holder MediaProjectionHolder) void
+detachMediaProjection() void
+init(screencapMethods long, inputMethods long) bool
+connect() bool
+requestUuid() String
+startApp(intent String) Boolean
+stopApp(intent String) Boolean
+tap(x Int, y Int) Boolean
+swipe(x1 Int, y1 Int, x2 Int, y2 Int, duration Int) Boolean
+scroll(dx Int, dy Int) Boolean
+keyEvent(key Int, down Boolean) Boolean
+inputText(text String) Boolean
+screencap() Bitmap
+getScreenSize() IntArray
}
class MaaAccessibilityService {
+onServiceConnected() void
+onUnbind(intent Intent) Boolean
+onAccessibilityEvent(event AccessibilityEvent) void
+onInterrupt() void
+uuid() String
+getScreenSize() IntArray
+startApp(intentUri String) Boolean
+stopApp(intentUri String) Boolean
+tap(x Int, y Int) Boolean
+swipe(x1 Int, y1 Int, x2 Int, y2 Int, duration Int) Boolean
+scroll(dx Int, dy Int) Boolean
+keyEvent(key Int, down Boolean) Boolean
+inputText(text String) Boolean
+screencap() Bitmap
}
class MediaProjectionHolder {
-context Context
-mediaProjection MediaProjection
-virtualDisplay VirtualDisplay
-imageReader ImageReader
-handlerThread HandlerThread
-handler Handler
+MediaProjectionHolder(context Context, mediaProjection MediaProjection)
+capture() Bitmap
+release() void
-initScreen() void
-setupImageReader() void
-imageToBitmap(image Image) Bitmap
}
class MediaProjectionActivity {
+onCreate(savedInstanceState Bundle) void
+onActivityResult(requestCode Int, resultCode Int, data Intent) void
+onDestroy() void
+requestPermission(context Context, callback Function) void
-clearCallback() void
}
ControlUnitAPI <|-- AndroidControlUnitAPI
AndroidControlUnitAPI <|-- AndroidControlUnitMgr
AndroidControlUnitLibraryHolder ..> AndroidControlUnitAPI : creates
AndroidControlUnitMgr ..> NativeBridge : uses_via_JNI
MaaAndroidControlUnit_API ..> AndroidControlUnitMgr : returns_instance
ControllerAgent ..> ControlUnitAPI : holds_shared_ptr
MaaFramework_API ..> ControllerAgent : constructs
Runner ..> RuntimeParam : uses
RuntimeParam o-- AndroidParam
Runner ..> MaaFramework_API : calls_MaaAndroidControllerCreate
NativeBridge ..> MaaAccessibilityService : holds_reference
NativeBridge ..> MediaProjectionHolder : holds_reference
MaaAccessibilityService ..> NativeBridge : calls_attach_detach
MediaProjectionActivity ..> MediaProjectionHolder : creates_and_attaches
MediaProjectionActivity ..> NativeBridge : attachMediaProjection
文件级变更
Tips and commandsInteracting with Sourcery
Customizing Your Experience进入你的 dashboard 以:
Getting HelpOriginal review guide in EnglishReviewer's GuideAdds a native Android controller implementation backed by an Android control unit shared library and Kotlin accessibility/MediaProjection bridge, wires it into the framework API/CLI/types, and updates build/test workflows to build and package the Android artifacts. Sequence diagram for creating and using an Android controllersequenceDiagram
actor User
participant Cli as MaaPiCli_Runner
participant Framework as MaaAndroidControllerCreate
participant LibHolder as AndroidControlUnitLibraryHolder
participant So as MaaAndroidControlUnit_so
participant CU as AndroidControlUnitMgr
participant JVM as JVM_ART
participant Bridge as NativeBridge
participant AccSvc as MaaAccessibilityService
User->>Cli: run(param with AndroidParam)
Cli->>Framework: MaaAndroidControllerCreate(screencap_methods, input_methods)
activate Framework
Framework->>LibHolder: create_control_unit(screencap_methods, input_methods)
activate LibHolder
LibHolder->>So: MaaAndroidControlUnitCreate(screencap_methods, input_methods)
activate So
So->>So: new AndroidControlUnitMgr
So-->>LibHolder: AndroidControlUnitHandle
deactivate So
LibHolder-->>Framework: shared_ptr AndroidControlUnitAPI
deactivate LibHolder
Framework->>Framework: new ControllerAgent(control_unit)
Framework-->>Cli: MaaController*
deactivate Framework
Note over Cli,Cli: Later, during controller initialization
Cli->>CU: connect()
activate CU
CU->>JVM: ensure_env()
CU->>Bridge: init(screencap_methods, input_methods)
CU->>Bridge: connect()
activate Bridge
Bridge->>Bridge: verify accessibility/media_projection availability
Bridge-->>CU: true/false
deactivate Bridge
CU-->>Cli: connect result
deactivate CU
Note over CU,Bridge: During operations (example: screencap)
Cli->>CU: screencap(image)
activate CU
CU->>Bridge: screencap()
activate Bridge
alt MediaProjection enabled and available
Bridge->>Bridge: mediaProjectionHolder.capture()
else Accessibility screenshot fallback
Bridge->>AccSvc: screencap()
activate AccSvc
AccSvc-->>Bridge: Bitmap
deactivate AccSvc
end
Bridge-->>CU: Bitmap
deactivate Bridge
CU-->>Cli: fill cv::Mat from Bitmap
deactivate CU
Class diagram for new Android control unit and Kotlin bridgeclassDiagram
direction LR
class ControlUnitAPI {
<<abstract>>
+connect() bool
+request_uuid(uuid string) bool
+get_features() MaaControllerFeature
+start_app(intent string) bool
+stop_app(intent string) bool
+screencap(image cv_Mat) bool
+click(x int, y int) bool
+swipe(x1 int, y1 int, x2 int, y2 int, duration int) bool
+touch_down(contact int, x int, y int, pressure int) bool
+touch_move(contact int, x int, y int, pressure int) bool
+touch_up(contact int) bool
+click_key(key int) bool
+input_text(text string) bool
+key_down(key int) bool
+key_up(key int) bool
+scroll(dx int, dy int) bool
}
class AndroidControlUnitAPI {
<<abstract>>
}
class AndroidControlUnitMgr {
-screencap_methods_ MaaAndroidScreencapMethod
-input_methods_ MaaAndroidInputMethod
-vm_ JavaVM*
-bridge_cls_ jclass
+AndroidControlUnitMgr(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod)
+connect() bool
+request_uuid(uuid string) bool
+get_features() MaaControllerFeature
+start_app(intent string) bool
+stop_app(intent string) bool
+screencap(image cv_Mat) bool
+click(x int, y int) bool
+swipe(x1 int, y1 int, x2 int, y2 int, duration int) bool
+touch_down(contact int, x int, y int, pressure int) bool
+touch_move(contact int, x int, y int, pressure int) bool
+touch_up(contact int) bool
+click_key(key int) bool
+input_text(text string) bool
+key_down(key int) bool
+key_up(key int) bool
+scroll(dx int, dy int) bool
-ensure_env() JNIEnv*
-bridge_class() jclass
-call_bool(name char*, sig char*, caller Callable) bool
}
class AndroidControlUnitLibraryHolder {
+create_control_unit(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod) shared_ptr~AndroidControlUnitAPI~
-libname_ filesystem_path
-version_func_name_ string
-create_func_name_ string
-destroy_func_name_ string
}
class MaaAndroidControlUnit_API {
+MaaAndroidControlUnitGetVersion() const_char_ptr
+MaaAndroidControlUnitCreate(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod) MaaAndroidControlUnitHandle
+MaaAndroidControlUnitDestroy(handle MaaAndroidControlUnitHandle) void
}
class MaaController {
}
class ControllerAgent {
+ControllerAgent(control_unit shared_ptr~ControlUnitAPI~)
}
class MaaFramework_API {
+MaaAndroidControllerCreate(screencap_methods MaaAndroidScreencapMethod, input_methods MaaAndroidInputMethod) MaaController*
}
class RuntimeParam {
+controller_param variant
}
class AndroidParam {
+screencap MaaAndroidScreencapMethod
+input MaaAndroidInputMethod
}
class Runner {
+run(param RuntimeParam) bool
}
class NativeBridge {
<<object>>
+SCREENCAP_METHOD_NONE long
+SCREENCAP_METHOD_ACCESSIBILITY long
+SCREENCAP_METHOD_MEDIA_PROJECTION long
+INPUT_METHOD_NONE long
+INPUT_METHOD_ACCESSIBILITY long
-accessibilityService MaaAccessibilityService
-mediaProjectionHolder MediaProjectionHolder
-screencapMethods long
-inputMethods long
+attachAccessibilityService(service MaaAccessibilityService) void
+detachAccessibilityService(service MaaAccessibilityService) void
+attachMediaProjection(holder MediaProjectionHolder) void
+detachMediaProjection() void
+init(screencapMethods long, inputMethods long) bool
+connect() bool
+requestUuid() String
+startApp(intent String) Boolean
+stopApp(intent String) Boolean
+tap(x Int, y Int) Boolean
+swipe(x1 Int, y1 Int, x2 Int, y2 Int, duration Int) Boolean
+scroll(dx Int, dy Int) Boolean
+keyEvent(key Int, down Boolean) Boolean
+inputText(text String) Boolean
+screencap() Bitmap
+getScreenSize() IntArray
}
class MaaAccessibilityService {
+onServiceConnected() void
+onUnbind(intent Intent) Boolean
+onAccessibilityEvent(event AccessibilityEvent) void
+onInterrupt() void
+uuid() String
+getScreenSize() IntArray
+startApp(intentUri String) Boolean
+stopApp(intentUri String) Boolean
+tap(x Int, y Int) Boolean
+swipe(x1 Int, y1 Int, x2 Int, y2 Int, duration Int) Boolean
+scroll(dx Int, dy Int) Boolean
+keyEvent(key Int, down Boolean) Boolean
+inputText(text String) Boolean
+screencap() Bitmap
}
class MediaProjectionHolder {
-context Context
-mediaProjection MediaProjection
-virtualDisplay VirtualDisplay
-imageReader ImageReader
-handlerThread HandlerThread
-handler Handler
+MediaProjectionHolder(context Context, mediaProjection MediaProjection)
+capture() Bitmap
+release() void
-initScreen() void
-setupImageReader() void
-imageToBitmap(image Image) Bitmap
}
class MediaProjectionActivity {
+onCreate(savedInstanceState Bundle) void
+onActivityResult(requestCode Int, resultCode Int, data Intent) void
+onDestroy() void
+requestPermission(context Context, callback Function) void
-clearCallback() void
}
ControlUnitAPI <|-- AndroidControlUnitAPI
AndroidControlUnitAPI <|-- AndroidControlUnitMgr
AndroidControlUnitLibraryHolder ..> AndroidControlUnitAPI : creates
AndroidControlUnitMgr ..> NativeBridge : uses_via_JNI
MaaAndroidControlUnit_API ..> AndroidControlUnitMgr : returns_instance
ControllerAgent ..> ControlUnitAPI : holds_shared_ptr
MaaFramework_API ..> ControllerAgent : constructs
Runner ..> RuntimeParam : uses
RuntimeParam o-- AndroidParam
Runner ..> MaaFramework_API : calls_MaaAndroidControllerCreate
NativeBridge ..> MaaAccessibilityService : holds_reference
NativeBridge ..> MediaProjectionHolder : holds_reference
MaaAccessibilityService ..> NativeBridge : calls_attach_detach
MediaProjectionActivity ..> MediaProjectionHolder : creates_and_attaches
MediaProjectionActivity ..> NativeBridge : attachMediaProjection
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好,我已经审查了你的修改,发现有一些需要处理的问题。
- AndroidControlUnitMgr 在 bridge_cls_ 中缓存了指向 NativeBridge 的全局引用,但从未释放;请考虑删除该全局引用(例如在管理器析构函数或专门的关闭路径中)以避免在进程生命周期内泄漏 JNI 全局引用。
- ensure_env() 可能会将任意线程附加到 JVM 上,但从不将其分离;如果 MaaFramework 在控制器操作中可能使用许多不同的线程,那么最好明确一个线程生命周期策略,或者添加一个在线程结束时调用 DetachCurrentThread 的 RAII 辅助工具,以提高安全性。
面向 AI Agent 的提示
请根据这次代码审查的评论进行修改:
## 总体评论
- AndroidControlUnitMgr 在 bridge_cls_ 中缓存了指向 NativeBridge 的全局引用,但从未释放;请考虑删除该全局引用(例如在管理器析构函数或专门的关闭路径中)以避免在进程生命周期内泄漏 JNI 全局引用。
- ensure_env() 可能会将任意线程附加到 JVM 上,但从不将其分离;如果 MaaFramework 在控制器操作中可能使用许多不同的线程,那么最好明确一个线程生命周期策略,或者添加一个在线程结束时调用 DetachCurrentThread 的 RAII 辅助工具,以提高安全性。
## 逐条评论
### 评论 1
<location> `include/MaaFramework/MaaDef.h:269-271` </location>
<code_context>
+/**
+ * Use bitwise OR to set the method you need.
+ */
+typedef uint64_t MaaAndroidInputMethod;
+#define MaaAndroidInputMethod_None 0ULL
+#define MaaAndroidInputMethod_Accessibility 1ULL
+
// MaaWin32ScreencapMethod:
</code_context>
<issue_to_address>
**issue (bug_risk):** 定义 MaaAndroidInputMethod_All 和 MaaAndroidInputMethod_Default 以与模块导出和用法保持一致
`MaaFramework.cppm` 导出了 `_MaaAndroidInputMethod_All` / `_MaaAndroidInputMethod_Default`,并引用了 `MaaAndroidInputMethod_All` / `MaaAndroidInputMethod_Default`,但这些宏在此处没有定义。这会导致编译或链接错误。请在这里定义它们(例如:
```c
#define MaaAndroidInputMethod_All (~MaaAndroidInputMethod_None)
#define MaaAndroidInputMethod_Default MaaAndroidInputMethod_Accessibility
```
或者使用你偏好的语义),以保证 C API 与模块导出保持一致。
</issue_to_address>
### 评论 2
<location> `source/MaaAndroidControlUnit/Manager/AndroidControlUnitMgr.cpp:180-189` </location>
<code_context>
+bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 明确或调整像素格式处理,以匹配预期的 OpenCV 通道顺序
`image` 始终以 `CV_8UC4` 创建,但对于 `RGBA_8888` 位图,你似乎是按原样复制通道,而 RGB565 路径则构造了类似 BGRA 的布局(`b, g, r, 255`)。如果后续处理流水线假定特定的通道顺序(通常是 BGRA),那么 `RGBA_8888` 路径可能会导致颜色通道对调。建议显式地将所有输入转换为一个统一且有文档说明的通道顺序(例如通过 `cv::cvtColor` 或手动通道交换),以保证跨平台行为一致。
建议实现:
```cpp
bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image)
{
// NOTE: All outputs from this function are expected to be BGRA (CV_8UC4).
// Be sure to convert any other input formats (e.g. RGBA_8888) accordingly.
JNIEnv* env = ensure_env();
if (!env) {
LogError << "JNIEnv null";
return false;
}
jclass cls = bridge_class();
if (!cls) {
return false;
}
```
```cpp
case ANDROID_BITMAP_FORMAT_RGBA_8888: {
// Convert RGBA_8888 input into a BGRA CV_8UC4 Mat to keep a consistent channel order.
cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);
cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);
break;
}
```
由于我目前只能看到 `screencap` 的开头部分,你可能需要根据现有代码对 `SEARCH` 区块进行适配:
1. 确保存在一个 `case ANDROID_BITMAP_FORMAT_RGBA_8888`(或等价的条件分支)来处理当前“按原样”复制 RGBA 像素到 `image` 的逻辑。将该分支体替换为:
- 使用临时 `cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);` 包装 `bitmapPixels`
- 调用 `cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);`
2. 如果 RGBA 路径当前是 `image = cv::Mat(height, width, CV_8UC4);` 然后再手动拷贝到 `image.data`,请移除该手动拷贝,改用 `cv::Mat rgba(...)` + `cvtColor` 的方式,以避免重复分配或步幅不匹配。
3. 验证 RGB565 路径是否确实生成了 BGRA(`b, g, r, 255`),以确保“BGRA (CV_8UC4)” 这一预期是正确的;如果不是,要么调整 RGB565 转换也输出 BGRA,要么修改注释和 `cvtColor` 的目标格式以匹配你选择的规范通道顺序。
4. 确保在该翻译单元中包含 `<opencv2/imgproc.hpp>`(或相应的 OpenCV 头文件),以便可以使用 `cv::cvtColor` 和 `cv::COLOR_RGBA2BGRA`。
</issue_to_address>
### 评论 3
<location> `docs/en_us/2.4-ControlMethods.md:57` </location>
<code_context>
+
+| Name | Value | Description |
+| --- | --- | --- |
+| Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on current focused input node. |
+
+### Android Screencap
</code_context>
<issue_to_address>
**issue (typo):** 将 "current focused" 改为 "currently focused" 以符合正确的语法
将 "on current focused input node" 修改为 "on the currently focused input node",以保证语法正确且表达更清晰。
```suggestion
| Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on the currently focused input node. |
```
</issue_to_address>
### 评论 4
<location> `docs/en_us/2.4-ControlMethods.md:63` </location>
<code_context>
+
+> Reference: `MaaAndroidScreencapMethod`.
+
+Combine the selected methods below using **bitwise OR**. Framework will choose available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot.
+
+| Name | Value | Description |
</code_context>
<issue_to_address>
**suggestion (typo):** 建议在 "Framework will choose available ones" 中补充冠词,使语句更顺畅
可以改成这样以使表达更自然且语法完整:"The framework will choose the available ones, preferring MediaProjection …"。
```suggestion
Combine the selected methods below using **bitwise OR**. The framework will choose the available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot.
```
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey there - I've reviewed your changes and found some issues that need to be addressed.
- AndroidControlUnitMgr caches a global reference to NativeBridge in bridge_cls_ but never releases it; consider deleting the global ref (e.g. in the manager destructor or a dedicated shutdown path) to avoid leaking JNI global references over the lifetime of the process.
- ensure_env() may attach arbitrary threads to the JVM without ever detaching them; if MaaFramework can use many different threads for controller operations, it would be safer to define a clear thread-lifetime policy or add an RAII helper that calls DetachCurrentThread when threads are done.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- AndroidControlUnitMgr caches a global reference to NativeBridge in bridge_cls_ but never releases it; consider deleting the global ref (e.g. in the manager destructor or a dedicated shutdown path) to avoid leaking JNI global references over the lifetime of the process.
- ensure_env() may attach arbitrary threads to the JVM without ever detaching them; if MaaFramework can use many different threads for controller operations, it would be safer to define a clear thread-lifetime policy or add an RAII helper that calls DetachCurrentThread when threads are done.
## Individual Comments
### Comment 1
<location> `include/MaaFramework/MaaDef.h:269-271` </location>
<code_context>
+/**
+ * Use bitwise OR to set the method you need.
+ */
+typedef uint64_t MaaAndroidInputMethod;
+#define MaaAndroidInputMethod_None 0ULL
+#define MaaAndroidInputMethod_Accessibility 1ULL
+
// MaaWin32ScreencapMethod:
</code_context>
<issue_to_address>
**issue (bug_risk):** Define MaaAndroidInputMethod_All and MaaAndroidInputMethod_Default to match module exports and usage
`MaaFramework.cppm` exports `_MaaAndroidInputMethod_All` / `_MaaAndroidInputMethod_Default` and refers to `MaaAndroidInputMethod_All` / `MaaAndroidInputMethod_Default`, but these macros are not defined here. That will cause compile or link errors. Please define them (e.g.
```c
#define MaaAndroidInputMethod_All (~MaaAndroidInputMethod_None)
#define MaaAndroidInputMethod_Default MaaAndroidInputMethod_Accessibility
```
or whatever semantics you prefer) so the C API and module exports remain consistent.
</issue_to_address>
### Comment 2
<location> `source/MaaAndroidControlUnit/Manager/AndroidControlUnitMgr.cpp:180-189` </location>
<code_context>
+bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Clarify or adjust pixel format handling to match the expected OpenCV channel order
`image` is always created as `CV_8UC4`, but for `RGBA_8888` bitmaps you appear to copy channels as-is while the RGB565 path builds a BGRA-like layout (`b, g, r, 255`). If the rest of the pipeline assumes a specific ordering (commonly BGRA), the `RGBA_8888` path may produce swapped colors. Consider explicitly converting all inputs to a single, documented channel order (e.g., via `cv::cvtColor` or a manual channel swap) to keep behavior consistent across platforms.
Suggested implementation:
```cpp
bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image)
{
// NOTE: All outputs from this function are expected to be BGRA (CV_8UC4).
// Be sure to convert any other input formats (e.g. RGBA_8888) accordingly.
JNIEnv* env = ensure_env();
if (!env) {
LogError << "JNIEnv null";
return false;
}
jclass cls = bridge_class();
if (!cls) {
return false;
}
```
```cpp
case ANDROID_BITMAP_FORMAT_RGBA_8888: {
// Convert RGBA_8888 input into a BGRA CV_8UC4 Mat to keep a consistent channel order.
cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);
cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);
break;
}
```
Because I only see the beginning of `screencap`, you’ll likely need to adapt the `SEARCH` blocks to the exact existing code:
1. Ensure that there is a `case ANDROID_BITMAP_FORMAT_RGBA_8888` (or equivalent conditional handling) where RGBA pixels are currently copied “as-is” into `image`. Replace that body with the version that:
- Wraps `bitmapPixels` in a temporary `cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);`
- Calls `cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);`
2. If the RGBA path currently assigns `image = cv::Mat(height, width, CV_8UC4);` and then performs a manual copy into `image.data`, you should remove that manual copy in favor of the `cv::Mat rgba(...)` + `cvtColor` approach to avoid double allocations or mismatched strides.
3. Verify that the RGB565 path is indeed producing BGRA (`b, g, r, 255`) so that the documented “BGRA (CV_8UC4)” expectation is correct; if it is not, adjust the RGB565 conversion so that it also outputs BGRA, or change the comment and the `cvtColor` target to match the chosen canonical order.
4. Make sure `<opencv2/imgproc.hpp>` (or the appropriate OpenCV header) is included in this translation unit so that `cv::cvtColor` and `cv::COLOR_RGBA2BGRA` are available.
</issue_to_address>
### Comment 3
<location> `docs/en_us/2.4-ControlMethods.md:57` </location>
<code_context>
+
+| Name | Value | Description |
+| --- | --- | --- |
+| Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on current focused input node. |
+
+### Android Screencap
</code_context>
<issue_to_address>
**issue (typo):** Use "currently focused" instead of "current focused" for correct grammar.
Change "on current focused input node" to "on the currently focused input node" for correct grammar and clarity.
```suggestion
| Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on the currently focused input node. |
```
</issue_to_address>
### Comment 4
<location> `docs/en_us/2.4-ControlMethods.md:63` </location>
<code_context>
+
+> Reference: `MaaAndroidScreencapMethod`.
+
+Combine the selected methods below using **bitwise OR**. Framework will choose available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot.
+
+| Name | Value | Description |
</code_context>
<issue_to_address>
**suggestion (typo):** Consider adding an article to "Framework will choose available ones" for smoother phrasing.
You could rephrase to: "The framework will choose the available ones, preferring MediaProjection …" for more natural, grammatically complete wording.
```suggestion
Combine the selected methods below using **bitwise OR**. The framework will choose the available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot.
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| typedef uint64_t MaaAndroidInputMethod; | ||
| #define MaaAndroidInputMethod_None 0ULL | ||
| #define MaaAndroidInputMethod_Accessibility 1ULL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): 定义 MaaAndroidInputMethod_All 和 MaaAndroidInputMethod_Default 以与模块导出和用法保持一致
MaaFramework.cppm 导出了 _MaaAndroidInputMethod_All / _MaaAndroidInputMethod_Default,并引用了 MaaAndroidInputMethod_All / MaaAndroidInputMethod_Default,但这些宏在此处没有定义。这会导致编译或链接错误。请在这里定义它们(例如:
#define MaaAndroidInputMethod_All (~MaaAndroidInputMethod_None)
#define MaaAndroidInputMethod_Default MaaAndroidInputMethod_Accessibility或者使用你偏好的语义),以保证 C API 与模块导出保持一致。
Original comment in English
issue (bug_risk): Define MaaAndroidInputMethod_All and MaaAndroidInputMethod_Default to match module exports and usage
MaaFramework.cppm exports _MaaAndroidInputMethod_All / _MaaAndroidInputMethod_Default and refers to MaaAndroidInputMethod_All / MaaAndroidInputMethod_Default, but these macros are not defined here. That will cause compile or link errors. Please define them (e.g.
#define MaaAndroidInputMethod_All (~MaaAndroidInputMethod_None)
#define MaaAndroidInputMethod_Default MaaAndroidInputMethod_Accessibilityor whatever semantics you prefer) so the C API and module exports remain consistent.
| bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image) | ||
| { | ||
| JNIEnv* env = ensure_env(); | ||
| if (!env) { | ||
| LogError << "JNIEnv null"; | ||
| return false; | ||
| } | ||
| jclass cls = bridge_class(); | ||
| if (!cls) { | ||
| return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): 明确或调整像素格式处理,以匹配预期的 OpenCV 通道顺序
image 始终以 CV_8UC4 创建,但对于 RGBA_8888 位图,你似乎是按原样复制通道,而 RGB565 路径则构造了类似 BGRA 的布局(b, g, r, 255)。如果后续处理流水线假定特定的通道顺序(通常是 BGRA),那么 RGBA_8888 路径可能会导致颜色通道对调。建议显式地将所有输入转换为一个统一且有文档说明的通道顺序(例如通过 cv::cvtColor 或手动通道交换),以保证跨平台行为一致。
建议实现:
bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image)
{
// NOTE: All outputs from this function are expected to be BGRA (CV_8UC4).
// Be sure to convert any other input formats (e.g. RGBA_8888) accordingly.
JNIEnv* env = ensure_env();
if (!env) {
LogError << "JNIEnv null";
return false;
}
jclass cls = bridge_class();
if (!cls) {
return false;
}
case ANDROID_BITMAP_FORMAT_RGBA_8888: {
// Convert RGBA_8888 input into a BGRA CV_8UC4 Mat to keep a consistent channel order.
cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);
cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);
break;
}
由于我目前只能看到 screencap 的开头部分,你可能需要根据现有代码对 SEARCH 区块进行适配:
- 确保存在一个
case ANDROID_BITMAP_FORMAT_RGBA_8888(或等价的条件分支)来处理当前“按原样”复制 RGBA 像素到image的逻辑。将该分支体替换为:- 使用临时
cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);包装bitmapPixels - 调用
cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);
- 使用临时
- 如果 RGBA 路径当前是
image = cv::Mat(height, width, CV_8UC4);然后再手动拷贝到image.data,请移除该手动拷贝,改用cv::Mat rgba(...)+cvtColor的方式,以避免重复分配或步幅不匹配。 - 验证 RGB565 路径是否确实生成了 BGRA(
b, g, r, 255),以确保“BGRA (CV_8UC4)” 这一预期是正确的;如果不是,要么调整 RGB565 转换也输出 BGRA,要么修改注释和cvtColor的目标格式以匹配你选择的规范通道顺序。 - 确保在该翻译单元中包含
<opencv2/imgproc.hpp>(或相应的 OpenCV 头文件),以便可以使用cv::cvtColor和cv::COLOR_RGBA2BGRA。
Original comment in English
suggestion (bug_risk): Clarify or adjust pixel format handling to match the expected OpenCV channel order
image is always created as CV_8UC4, but for RGBA_8888 bitmaps you appear to copy channels as-is while the RGB565 path builds a BGRA-like layout (b, g, r, 255). If the rest of the pipeline assumes a specific ordering (commonly BGRA), the RGBA_8888 path may produce swapped colors. Consider explicitly converting all inputs to a single, documented channel order (e.g., via cv::cvtColor or a manual channel swap) to keep behavior consistent across platforms.
Suggested implementation:
bool AndroidControlUnitMgr::screencap(/*out*/ cv::Mat& image)
{
// NOTE: All outputs from this function are expected to be BGRA (CV_8UC4).
// Be sure to convert any other input formats (e.g. RGBA_8888) accordingly.
JNIEnv* env = ensure_env();
if (!env) {
LogError << "JNIEnv null";
return false;
}
jclass cls = bridge_class();
if (!cls) {
return false;
}
case ANDROID_BITMAP_FORMAT_RGBA_8888: {
// Convert RGBA_8888 input into a BGRA CV_8UC4 Mat to keep a consistent channel order.
cv::Mat rgba(height, width, CV_8UC4, bitmapPixels);
cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);
break;
}
Because I only see the beginning of screencap, you’ll likely need to adapt the SEARCH blocks to the exact existing code:
- Ensure that there is a
case ANDROID_BITMAP_FORMAT_RGBA_8888(or equivalent conditional handling) where RGBA pixels are currently copied “as-is” intoimage. Replace that body with the version that:- Wraps
bitmapPixelsin a temporarycv::Mat rgba(height, width, CV_8UC4, bitmapPixels); - Calls
cv::cvtColor(rgba, image, cv::COLOR_RGBA2BGRA);
- Wraps
- If the RGBA path currently assigns
image = cv::Mat(height, width, CV_8UC4);and then performs a manual copy intoimage.data, you should remove that manual copy in favor of thecv::Mat rgba(...)+cvtColorapproach to avoid double allocations or mismatched strides. - Verify that the RGB565 path is indeed producing BGRA (
b, g, r, 255) so that the documented “BGRA (CV_8UC4)” expectation is correct; if it is not, adjust the RGB565 conversion so that it also outputs BGRA, or change the comment and thecvtColortarget to match the chosen canonical order. - Make sure
<opencv2/imgproc.hpp>(or the appropriate OpenCV header) is included in this translation unit so thatcv::cvtColorandcv::COLOR_RGBA2BGRAare available.
| | Name | Value | Description | | ||
| | --- | --- | --- | | ||
| | Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on current focused input node. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (typo): 将 "current focused" 改为 "currently focused" 以符合正确的语法
将 "on current focused input node" 修改为 "on the currently focused input node",以保证语法正确且表达更清晰。
| | Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on current focused input node. | | |
| | Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on the currently focused input node. | |
Original comment in English
issue (typo): Use "currently focused" instead of "current focused" for correct grammar.
Change "on current focused input node" to "on the currently focused input node" for correct grammar and clarity.
| | Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on current focused input node. | | |
| | Accessibility | `1` | Uses accessibility service for control, including `dispatchGesture` for tap/swipe/scroll, global actions for key events (back/home/recents), and `ACTION_SET_TEXT` on the currently focused input node. | |
|
|
||
| > Reference: `MaaAndroidScreencapMethod`. | ||
| Combine the selected methods below using **bitwise OR**. Framework will choose available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (typo): 建议在 "Framework will choose available ones" 中补充冠词,使语句更顺畅
可以改成这样以使表达更自然且语法完整:"The framework will choose the available ones, preferring MediaProjection …"。
| Combine the selected methods below using **bitwise OR**. Framework will choose available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot. | |
| Combine the selected methods below using **bitwise OR**. The framework will choose the available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot. |
Original comment in English
suggestion (typo): Consider adding an article to "Framework will choose available ones" for smoother phrasing.
You could rephrase to: "The framework will choose the available ones, preferring MediaProjection …" for more natural, grammatically complete wording.
| Combine the selected methods below using **bitwise OR**. Framework will choose available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot. | |
| Combine the selected methods below using **bitwise OR**. The framework will choose the available ones, preferring MediaProjection (faster and more stable), then AccessibilityScreenshot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds native Android controller support to the MaaFramework, enabling direct device control through Android Accessibility Services and MediaProjection APIs. This is a significant addition that allows the framework to run natively on Android devices without requiring ADB connections.
- Implements a new
AndroidControlUnitAPIwith JNI bridge to Kotlin/Java accessibility and media projection services - Adds Android-specific screencap methods (AccessibilityScreenshot for API 33+ and MediaProjection) and Accessibility input method
- Integrates the new controller into the CLI, CMake build system, and GitHub Actions workflow
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
source/modules/MaaFramework.cppm |
Exports new Android controller types and method constants |
source/include/ProjectInterface/Types.h |
Adds Android controller type and AndroidParam configuration |
source/include/LibraryHolder/ControlUnit.h |
Declares Android control unit library holder |
source/include/ControlUnit/ControlUnitAPI.h |
Defines AndroidControlUnitAPI interface and adds <vector> include |
source/include/ControlUnit/AndroidControlUnitAPI.h |
New header declaring Android control unit C API functions |
source/MaaPiCli/Impl/Runner.cpp |
Integrates Android controller creation in CLI runner |
source/MaaPiCli/Impl/Configurator.cpp |
Adds Android controller configuration generation |
source/MaaPiCli/CLI/interactor.cpp |
Adds Android controller selection and display in CLI |
source/MaaFramework/CMakeLists.txt |
Adds Android control unit build dependency |
source/MaaFramework/API/MaaFramework.cpp |
Implements MaaAndroidControllerCreate with Android platform check |
source/MaaAndroidControlUnit/java/settings.gradle.kts |
New Gradle settings for Android library |
source/MaaAndroidControlUnit/java/res/xml/accessibility_service_config.xml |
Configures accessibility service capabilities |
source/MaaAndroidControlUnit/java/gradle.properties |
Gradle properties for AndroidX and Kotlin |
source/MaaAndroidControlUnit/java/com/maa/framework/nativectrl/NativeBridge.kt |
JNI bridge singleton coordinating native and Java/Kotlin layers |
source/MaaAndroidControlUnit/java/com/maa/framework/nativectrl/MediaProjectionHolder.kt |
Manages MediaProjection for screen capture with virtual display |
source/MaaAndroidControlUnit/java/com/maa/framework/nativectrl/MediaProjectionActivity.kt |
Transparent activity requesting MediaProjection permission |
source/MaaAndroidControlUnit/java/com/maa/framework/nativectrl/MaaAccessibilityService.kt |
Accessibility service implementing gesture dispatch, screenshot, and input |
source/MaaAndroidControlUnit/java/build.gradle.kts |
Gradle build configuration for Android library module |
source/MaaAndroidControlUnit/java/AndroidManifest.xml |
Declares accessibility service and MediaProjection activity |
source/MaaAndroidControlUnit/Manager/AndroidControlUnitMgr.h |
Header for Android control unit manager with JNI integration |
source/MaaAndroidControlUnit/Manager/AndroidControlUnitMgr.cpp |
Implements JNI calls to Kotlin bridge for all controller operations |
source/MaaAndroidControlUnit/CMakeLists.txt |
CMake configuration building Android control unit native library |
source/MaaAndroidControlUnit/API/AndroidControlUnitAPI.cpp |
Implements C API for creating/destroying Android control units |
source/LibraryHolder/ControlUnit/ControlUnit.cpp |
Adds Android control unit library loading and instantiation |
source/LibraryHolder/CMakeLists.txt |
Adds Android control unit dependency |
source/CMakeLists.txt |
Adds Android control unit subdirectory with platform check |
include/MaaFramework/MaaDef.h |
Defines Android screencap and input method types and constants |
include/MaaFramework/Instance/MaaController.h |
Declares MaaAndroidControllerCreate function |
docs/en_us/2.4-ControlMethods.md |
Documents Android input and screencap methods |
docs/en_us/2.2-IntegratedInterfaceOverview.md |
Documents MaaAndroidControllerCreate API |
CMakeLists.txt |
Adds WITH_ANDROID_CONTROLLER build option |
.github/workflows/build.yml |
Adds JDK, Gradle setup and Kotlin library build for Android workflow |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
|
|
||
| // 检查是否有待处理的回调,如果没有则直接关闭 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency: "// 检查是否有待处理的回调,如果没有则直接关闭" should be "// Check if there's a pending callback, if not, close immediately"
| // 检查是否有待处理的回调,如果没有则直接关闭 | |
| // Check if there's a pending callback, if not, close immediately |
|
|
||
| override fun onDestroy() { | ||
| super.onDestroy() | ||
| // 确保在 Activity 销毁时清理回调 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency: "// 确保在 Activity 销毁时清理回调" should be "// Ensure callback is cleared when Activity is destroyed"
| // 确保在 Activity 销毁时清理回调 | |
| // Ensure callback is cleared when Activity is destroyed |
| */ | ||
| typedef uint64_t MaaAndroidInputMethod; | ||
| #define MaaAndroidInputMethod_None 0ULL | ||
| #define MaaAndroidInputMethod_Accessibility 1ULL |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing MaaAndroidInputMethod_All and MaaAndroidInputMethod_Default macros. For consistency with other input method definitions (like MaaAdbInputMethod), these should be defined. Suggested additions:
#define MaaAndroidInputMethod_All (~MaaAndroidInputMethod_None)
#define MaaAndroidInputMethod_Default MaaAndroidInputMethod_Accessibility| #define MaaAndroidInputMethod_Accessibility 1ULL | |
| #define MaaAndroidInputMethod_Accessibility 1ULL | |
| #define MaaAndroidInputMethod_All (~MaaAndroidInputMethod_None) | |
| #define MaaAndroidInputMethod_Default MaaAndroidInputMethod_Accessibility |
|
|
||
| - `screencap_methods`: bitmask of `MaaAndroidScreencapMethod` (AccessibilityScreenshot or MediaProjection) | ||
| - `input_methods`: use `MaaAndroidInputMethod_Accessibility` (control via accessibility service) | ||
| - `config`: extra config (reserved, can be empty) |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation mentions a config parameter that doesn't exist in the actual API signature. The MaaAndroidControllerCreate function only takes screencap_methods and input_methods parameters, not a config parameter.
| - `config`: extra config (reserved, can be empty) |
| context.startActivity(intent) | ||
| } | ||
|
|
||
| // 清理静态回调,防止内存泄漏 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency: "// 清理静态回调,防止内存泄漏" should be "// Clear static callback to prevent memory leak"
| // 清理静态回调,防止内存泄漏 | |
| // Clear static callback to prevent memory leak |
|
|
||
| if (requestCode == REQUEST_CODE_CAPTURE) { | ||
| val callback = pendingCallback | ||
| pendingCallback = null // 立即清理回调引用 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency: "// 立即清理回调引用" should be "// Clear callback reference immediately"
| pendingCallback = null // 立即清理回调引用 | |
| pendingCallback = null // Clear callback reference immediately |
| fun capture(): Bitmap? { | ||
| val reader = imageReader ?: return null | ||
|
|
||
| // 首先尝试获取已有的图像 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency with the codebase: "// 首先尝试获取已有的图像" should be "// First try to get existing image"
| // 首先尝试获取已有的图像 | |
| // First try to get existing image |
| null | ||
| } | ||
|
|
||
| // 如果没有现成的图像,等待下一帧 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency with the codebase: "// 如果没有现成的图像,等待下一帧" should be "// If no image is available, wait for the next frame"
| // 如果没有现成的图像,等待下一帧 | |
| // If no image is available, wait for the next frame |
| // Crop if needed | ||
| return if (rowPadding > 0) { | ||
| val cropped = Bitmap.createBitmap(bitmap, 0, 0, image.width, image.height) | ||
| bitmap.recycle() // 回收原始 bitmap 避免内存泄漏 |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment contains Chinese text. Please translate to English for consistency: "// 回收原始 bitmap 避免内存泄漏" should be "// Recycle original bitmap to avoid memory leak"
| bitmap.recycle() // 回收原始 bitmap 避免内存泄漏 | |
| bitmap.recycle() // Recycle original bitmap to avoid memory leak |
Summary by Sourcery
在框架、CLI、构建系统和文档中新增并集成原生 Android 控制器实现。
新功能:
AndroidControlUnit和AndroidControlUnitMgr,通过辅助功能(accessibility)和MediaProjection提供用于输入和截图的原生 Android 控制器。MaaAndroidControllerCreateAPI、Android 专用的截图与输入方式枚举,并通过 C++ 模块接口和 CLI 运行时配置对外暴露。MediaProjection支持,以及被原生 Android 控制单元使用的NativeBridge。增强:
MaaPiCli的配置器、运行器和交互器,以便选择并运行原生 Android 控制器。构建:
WITH_ANDROID_CONTROLLERCMake 标志、Android 专用的MaaAndroidControlUnit目标,并在 Android 平台构建时将其链接进主构建。文档:
MaaAndroidControllerCreate的使用说明。Original summary in English
Summary by Sourcery
Add a native Android controller implementation and integrate it into the framework, CLI, build system, and documentation.
New Features:
Enhancements:
Build:
Documentation: