重构代码,打印界面
This commit is contained in:
34
app/src/main/java/com/loveerror/bested/button/ActionEvent.kt
Normal file
34
app/src/main/java/com/loveerror/bested/button/ActionEvent.kt
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package com.loveerror.bested.button
|
||||||
|
|
||||||
|
enum class ActionEvent {
|
||||||
|
|
||||||
|
START_ACTION("com.loveerror.bested.START_ACTION", "启动按钮"),
|
||||||
|
FILL_ACTION("com.loveerror.bested.FILL_ACTION", "填充表单"),
|
||||||
|
SET_DATA_SOURCE("com.loveerror.bested.SET_DATA_SOURCE", "设置数据源"),
|
||||||
|
HIDE_FLOATING_BUTTON("com.loveerror.bested.HIDE_FLOATING_BUTTON", "隐藏悬浮按钮"),
|
||||||
|
PRINT_CURRENT_PAGE("com.loveerror.bested.PRINT_CURRENT_PAGE", "打印当前界面"),
|
||||||
|
|
||||||
|
UNKNOWN("com.loveerror.bested.UNKNOWN", "未知",isDisplay = false);
|
||||||
|
|
||||||
|
constructor(event: String, menuName: String, isDisplay: Boolean = true){
|
||||||
|
this.event = event
|
||||||
|
this.menuName = menuName
|
||||||
|
this.isDisplay = isDisplay
|
||||||
|
}
|
||||||
|
|
||||||
|
val menuName: String
|
||||||
|
val event: String
|
||||||
|
|
||||||
|
val isDisplay: Boolean
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getByMenuName(menuName: String) :ActionEvent {
|
||||||
|
for (item in ActionEvent.entries){
|
||||||
|
if (item.menuName == menuName){
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,67 +118,31 @@ class DragFloatingButton(context: Context) : View(context) {
|
|||||||
|
|
||||||
private fun showPopupMenu() {
|
private fun showPopupMenu() {
|
||||||
val popup = PopupMenu(context, this)
|
val popup = PopupMenu(context, this)
|
||||||
popup.menu.add("启动按钮")
|
// 添加菜单项 use ActionEvent
|
||||||
popup.menu.add("填充表单")
|
for (item in ActionEvent.entries){
|
||||||
popup.menu.add("设置数据源")
|
if (item.isDisplay) {
|
||||||
popup.menu.add("隐藏悬浮按钮")
|
popup.menu.add(item.menuName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener { item ->
|
popup.setOnMenuItemClickListener { item ->
|
||||||
when (item.title) {
|
val actionEvent = ActionEvent.getByMenuName(item.title.toString())
|
||||||
"启动按钮" -> {
|
try {
|
||||||
performStartAction()
|
context.sendBroadcast(android.content.Intent(actionEvent.event).apply {
|
||||||
true
|
setPackage(context.packageName)
|
||||||
}
|
})
|
||||||
"填充表单" -> {
|
} catch (e: IllegalArgumentException) {
|
||||||
performFillFormAction()
|
// 处理枚举值不存在的情况
|
||||||
true
|
e.printStackTrace()
|
||||||
}
|
println("枚举值不存在: ${item.title},${actionEvent}, ${e.toString()}")
|
||||||
"设置数据源" -> {
|
|
||||||
performSetDataSource()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
"隐藏悬浮按钮" -> {
|
|
||||||
hideFloatingButton()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
popup.show()
|
popup.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performStartAction() {
|
|
||||||
// 执行启动按钮操作
|
|
||||||
context.sendBroadcast(android.content.Intent("com.loveerror.bested.START_ACTION").apply {
|
|
||||||
setPackage(context.packageName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun performSetDataSource() {
|
|
||||||
// 执行设置数据源操作
|
|
||||||
context.sendBroadcast(android.content.Intent("com.loveerror.bested.SET_DATA_SOURCE").apply {
|
|
||||||
setPackage(context.packageName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideFloatingButton() {
|
|
||||||
context.sendBroadcast(android.content.Intent("com.loveerror.bested.HIDE_FLOATING_BUTTON").apply {
|
|
||||||
setPackage(context.packageName)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 或者直接通过 WindowManager 移除视图
|
|
||||||
try {
|
|
||||||
windowManager.removeView(this)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// 处理可能的异常
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DragFloatingButton.performFillFormAction() {
|
|
||||||
// 执行启动按钮操作
|
|
||||||
context.sendBroadcast(android.content.Intent("com.loveerror.bested.FILL_ACTION").apply {
|
|
||||||
setPackage(context.packageName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ class GlobalFloatingButtonManager(private val context: Context) {
|
|||||||
broadcastReceiver = object : BroadcastReceiver() {
|
broadcastReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
"com.loveerror.bested.HIDE_FLOATING_BUTTON" -> {
|
ActionEvent.HIDE_FLOATING_BUTTON.event -> {
|
||||||
hideFloatingButton()
|
hideFloatingButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val filter = IntentFilter("com.loveerror.bested.HIDE_FLOATING_BUTTON")
|
val filter = IntentFilter(ActionEvent.HIDE_FLOATING_BUTTON.event)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
context.registerReceiver(broadcastReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
|
context.registerReceiver(broadcastReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,147 +1,308 @@
|
|||||||
package com.loveerror.bested.handler
|
package com.loveerror.bested.handler
|
||||||
|
|
||||||
import android.view.accessibility.AccessibilityNodeInfo
|
import android.view.accessibility.AccessibilityNodeInfo
|
||||||
|
import com.loveerror.bested.UIInspectorService
|
||||||
import com.loveerror.bested.tool.AccessibilityTool
|
import com.loveerror.bested.tool.AccessibilityTool
|
||||||
import com.loveerror.bested.tool.NodeToolHint
|
import com.loveerror.bested.tool.NodeToolHint
|
||||||
import com.loveerror.bested.tool.NodeToolText
|
import com.loveerror.bested.tool.NodeToolText
|
||||||
|
|
||||||
class NormalGroupCreateForm {
|
class NormalGroupCreateForm (private val uiInspectorService: UIInspectorService){
|
||||||
companion object{
|
|
||||||
|
|
||||||
class FieldName {
|
|
||||||
|
|
||||||
val fieldName: String
|
|
||||||
val hintText: String
|
|
||||||
val defaultValue: String
|
|
||||||
val type: FieldType
|
|
||||||
|
|
||||||
constructor(fieldName: String, hintText: String, defaultValue: String, type: FieldType){
|
class FieldName {
|
||||||
this.fieldName = fieldName
|
|
||||||
this.hintText = hintText
|
val fieldName: String
|
||||||
this.defaultValue = defaultValue
|
val hintText: String
|
||||||
this.type = type
|
val defaultValue: String
|
||||||
|
val type: FieldType
|
||||||
|
|
||||||
|
constructor(fieldName: String, hintText: String, defaultValue: String, type: FieldType = FieldType.TEXT){
|
||||||
|
this.fieldName = fieldName
|
||||||
|
this.hintText = hintText
|
||||||
|
this.defaultValue = defaultValue
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class FieldType {
|
||||||
|
TEXT,
|
||||||
|
SELECT,
|
||||||
|
CHECKBOX,
|
||||||
|
RADIO,
|
||||||
|
DATE,
|
||||||
|
TIME,
|
||||||
|
NUMBER,
|
||||||
|
CURRENCY,
|
||||||
|
EMAIL,
|
||||||
|
PHONE,
|
||||||
|
ADDRESS,
|
||||||
|
URL,
|
||||||
|
PASSWORD,
|
||||||
|
FILE,
|
||||||
|
IMAGE,
|
||||||
|
VIDEO,
|
||||||
|
AUDIO,
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields = arrayListOf<FieldName>()
|
||||||
|
init {
|
||||||
|
fields.add(FieldName("集团名称", "请输入集团名称", "集团abc", FieldType.TEXT))
|
||||||
|
fields.add(FieldName("证件名称", "证件名称", "jituan", FieldType.TEXT))
|
||||||
|
fields.add(FieldName("证件号码", "请输入证件号码", "44010119900101001X", FieldType.TEXT))
|
||||||
|
fields.add(FieldName("法人代表", "请输入法人代表", "张三", FieldType.TEXT))
|
||||||
|
fields.add(FieldName("证件地址", "请输入证件地址", "北京市海淀区", FieldType.TEXT))
|
||||||
|
fields.add(FieldName("联系电话", "请输入联系电话", "13266667777", FieldType.TEXT))
|
||||||
|
fields.add(FieldName("员工数", "请输入人数", "1", FieldType.TEXT))
|
||||||
|
|
||||||
|
// select
|
||||||
|
fields.add(FieldName("集团状态", "", "潜在集团", FieldType.SELECT))
|
||||||
|
fields.add(FieldName("证件有效期", "", "2025", FieldType.SELECT))
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动填充普通集团建档表单
|
||||||
|
* @param root AccessibilityNodeInfo根节点
|
||||||
|
* @param groupName 集团名称
|
||||||
|
*/
|
||||||
|
fun autoFillForm(root: AccessibilityNodeInfo) {
|
||||||
|
|
||||||
|
val fieldMap = mapOf<String, String>(
|
||||||
|
"集团名称" to "集团abc2",
|
||||||
|
"证件名称" to "jituan2",
|
||||||
|
"证件号码" to "44010119900101001X",
|
||||||
|
"法人代表" to "张三2",
|
||||||
|
"证件地址" to "北京市海淀区2",
|
||||||
|
"联系电话" to "13288887777",
|
||||||
|
"员工数" to "2"
|
||||||
|
)
|
||||||
|
performBottomSheetSelection(root, "证件有效期", "2056")
|
||||||
|
|
||||||
|
// 先展开分类信息区域
|
||||||
|
// expandClassificationSection(root)
|
||||||
|
|
||||||
|
for(field in fields){
|
||||||
|
if (field.type == FieldType.SELECT){
|
||||||
|
performBottomSheetSelection(root, field.fieldName, fieldMap[field.fieldName] ?: field.defaultValue)
|
||||||
|
}else{
|
||||||
|
fillEditTextByHintText(root,fieldMap[field.fieldName] ?: field.defaultValue, field.fieldName, field.hintText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class FieldType {
|
AccessibilityTool.printViewTree(uiInspectorService.rootInActiveWindow,"after 已点击兄弟节点")
|
||||||
TEXT,
|
var rootNew = uiInspectorService.rootInActiveWindow
|
||||||
SELECT,
|
|
||||||
CHECKBOX,
|
|
||||||
RADIO,
|
|
||||||
DATE,
|
|
||||||
TIME,
|
|
||||||
NUMBER,
|
|
||||||
CURRENCY,
|
|
||||||
EMAIL,
|
|
||||||
PHONE,
|
|
||||||
ADDRESS,
|
|
||||||
URL,
|
|
||||||
PASSWORD,
|
|
||||||
FILE,
|
|
||||||
IMAGE,
|
|
||||||
VIDEO,
|
|
||||||
AUDIO,
|
|
||||||
OTHER
|
|
||||||
}
|
|
||||||
|
|
||||||
var fields = arrayListOf<FieldName>()
|
var peopleCountNode = NodeToolText.findNodeByText(rootNew,"请输入人数")
|
||||||
init {
|
|
||||||
fields.add(FieldName("集团名称", "请输入集团名称", "集团abc", FieldType.TEXT))
|
|
||||||
fields.add(FieldName("证件名称", "证件名称", "jituan", FieldType.TEXT))
|
|
||||||
fields.add(FieldName("证件号码", "请输入证件号码", "44010119900101001X", FieldType.TEXT))
|
|
||||||
fields.add(FieldName("法人代表", "请输入法人代表", "张三", FieldType.TEXT))
|
|
||||||
fields.add(FieldName("证件地址", "请输入证件地址", "北京市海淀区", FieldType.TEXT))
|
|
||||||
fields.add(FieldName("联系电话", "请输入联系电话", "13266667777", FieldType.TEXT))
|
|
||||||
fields.add(FieldName("员工数", "请输入人数", "1", FieldType.TEXT))
|
|
||||||
|
|
||||||
}
|
if (peopleCountNode == null){
|
||||||
/**
|
println("未找到员工数输入框")
|
||||||
* 自动填充普通集团建档表单
|
// 使用示例
|
||||||
* @param root AccessibilityNodeInfo根节点
|
val targetNode = NodeToolText.findNodeByText(root, "分类信息")
|
||||||
* @param groupName 集团名称
|
val nextSibling = NodeToolText.findNextSiblingNode(targetNode)
|
||||||
*/
|
|
||||||
fun autoFillForm(root: AccessibilityNodeInfo) {
|
|
||||||
|
|
||||||
val fieldMap = mapOf<String, String>(
|
if (nextSibling != null && nextSibling.isClickable) {
|
||||||
"集团名称" to "集团abc2",
|
// AccessibilityTool.focus(nextSibling)
|
||||||
"证件名称" to "jituan2",
|
AccessibilityTool.ensureNodeVisible(nextSibling)
|
||||||
"证件号码" to "44010119900101001X",
|
AccessibilityTool.performClick(nextSibling, false)
|
||||||
"法人代表" to "张三2",
|
|
||||||
"证件地址" to "北京市海淀区2",
|
|
||||||
"联系电话" to "13288887777",
|
|
||||||
"员工数" to "1"
|
|
||||||
)
|
|
||||||
// 查找并填写集团名称输入框
|
|
||||||
val groupName = "集团abc"
|
|
||||||
|
|
||||||
for(fieldName in fields){
|
Thread.sleep(1000)
|
||||||
fillEditTextByHintText(root,fieldMap[fieldName.fieldName] ?: fieldName.defaultValue, fieldName.fieldName, fieldName.hintText)
|
println("已点击兄弟节点")
|
||||||
|
// AccessibilityTool.printViewTree(uiInspectorService.rootInActiveWindow,"after 已点击兄弟节点")
|
||||||
|
} else {
|
||||||
|
println("未找到可点击的兄弟节点")
|
||||||
}
|
}
|
||||||
|
rootNew = uiInspectorService.rootInActiveWindow
|
||||||
|
peopleCountNode = NodeToolText.findNodeByText(rootNew,"请输入人数")
|
||||||
|
}
|
||||||
|
fillEditText(peopleCountNode, fieldMap["员工数"] ?: "1","员工数")
|
||||||
|
// fillEditTextByHintText(rootNew,fieldMap["员工数"] ?: "1", "员工数", "请输入人数")
|
||||||
|
|
||||||
|
// 示例:点击"集团状态"触发底部选择,选择"在网集团"
|
||||||
// fillCompanyNameField(root, groupName)
|
// fillCompanyNameField(root, groupName)
|
||||||
|
|
||||||
// 可以继续添加其他字段的填充逻辑
|
// 可以继续添加其他字段的填充逻辑
|
||||||
// 例如:选择集团状态、选择集团等级等
|
// 例如:选择集团状态、选择集团等级等
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 填写集团名称字段
|
|
||||||
* 根据UI树分析,查找hint为"请输入集团名称"的EditText并填入值
|
|
||||||
*/
|
|
||||||
private fun fillGroupNameField(root: AccessibilityNodeInfo, value: String) {
|
|
||||||
fillEditTextByHintText(root,value, "集团名称","请输入集团名称")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fillCompanyNameField(root: AccessibilityNodeInfo, value: String) {
|
// 点击可点击的触发元素来显示底部选择对话框
|
||||||
fillEditTextByHintText(root,value, "证件名称","证件名称")
|
fun clickToOpenBottomSheet(root: AccessibilityNodeInfo, triggerText: String) {
|
||||||
}
|
val triggerNode = NodeToolText.findNodeByText(root, triggerText)
|
||||||
|
if (triggerNode != null && triggerNode.isClickable) {
|
||||||
|
AccessibilityTool.ensureNodeVisible(triggerNode)
|
||||||
|
AccessibilityTool.performClick(triggerNode)
|
||||||
|
Thread.sleep(1000) // 等待对话框弹出
|
||||||
|
}else{
|
||||||
|
|
||||||
private fun fillEditTextByHintText(root: AccessibilityNodeInfo, value: String, fieldName : String, hintText: String) {
|
var parent = triggerNode?.parent
|
||||||
var editTextNode = NodeToolHint.findNodeByHint(root, hintText)
|
while (parent != null) {
|
||||||
fillEditText(editTextNode,value,fieldName)
|
if (parent.isClickable) {
|
||||||
}
|
AccessibilityTool.ensureNodeVisible(parent)
|
||||||
private fun fillEditText(editText: AccessibilityNodeInfo?, value: String, fieldName : String) {
|
AccessibilityTool.performClick(parent)
|
||||||
if (editText == null) {
|
return
|
||||||
return
|
}
|
||||||
}
|
parent = parent.parent
|
||||||
|
|
||||||
if (editText.isEditable) {
|
|
||||||
AccessibilityTool.inputText(editText, value)
|
|
||||||
println("已填写$fieldName: $value")
|
|
||||||
} else {
|
|
||||||
println("未找到${fieldName}输入框或输入框不可编辑")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 选择集团状态
|
|
||||||
* 根据UI树分析,可以通过点击相关视图来展开选项
|
|
||||||
*/
|
|
||||||
fun selectGroupStatus(root: AccessibilityNodeInfo, status: String = "在网集团") {
|
|
||||||
// 查找包含"在网集团"文本的TextView并点击
|
|
||||||
val statusView = NodeToolText.findNodeByText(root, status)
|
|
||||||
if (statusView != null && statusView.isClickable) {
|
|
||||||
AccessibilityTool.performClick(statusView)
|
|
||||||
println("已选择集团状态: $status")
|
|
||||||
} else {
|
|
||||||
println("未找到集团状态选项或选项不可点击")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 选择集团等级
|
|
||||||
* 根据UI树分析,可以通过点击相关视图来展开选项
|
|
||||||
*/
|
|
||||||
fun selectGroupLevel(root: AccessibilityNodeInfo, level: String = "D") {
|
|
||||||
// 查找包含"D"文本的TextView并点击
|
|
||||||
val levelView = NodeToolText.findNodeByText(root, level)
|
|
||||||
if (levelView != null && levelView.isClickable) {
|
|
||||||
AccessibilityTool.performClick(levelView)
|
|
||||||
println("已选择集团等级: $level")
|
|
||||||
} else {
|
|
||||||
println("未找到集团等级选项或选项不可点击")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 完整流程:点击触发 -> 选择选项
|
||||||
|
fun performBottomSheetSelection(root: AccessibilityNodeInfo, triggerText: String, optionText: String) {
|
||||||
|
// 1. 点击触发元素打开底部对话框
|
||||||
|
clickToOpenBottomSheet(root, triggerText)
|
||||||
|
|
||||||
|
// 2. 等待对话框完全显示
|
||||||
|
Thread.sleep(1000)
|
||||||
|
|
||||||
|
// 3. 选择目标选项
|
||||||
|
selectOptionFromBottomSheet(optionText)
|
||||||
|
|
||||||
|
// 4. 明确点击确认按钮 dubbo check
|
||||||
|
val newRoot = uiInspectorService.rootInActiveWindow
|
||||||
|
clickConfirmButton(newRoot)
|
||||||
|
Thread.sleep(500) // 等待确认操作完成
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在底部对话框中选择指定选项
|
||||||
|
fun selectOptionFromBottomSheet(optionText: String, confirm: Boolean = true) {
|
||||||
|
// 获取更新后的根节点
|
||||||
|
val newRoot = uiInspectorService.rootInActiveWindow
|
||||||
|
|
||||||
|
// 查找并点击选项
|
||||||
|
val optionNode = NodeToolText.findNodeByText(newRoot, optionText)
|
||||||
|
if (optionNode != null) {
|
||||||
|
AccessibilityTool.ensureNodeVisible(optionNode)
|
||||||
|
if (optionNode.isClickable) {
|
||||||
|
AccessibilityTool.performClick(optionNode)
|
||||||
|
println("已选择底部选项: $optionText")
|
||||||
|
|
||||||
|
// 根据需要点击确认或取消按钮
|
||||||
|
if (confirm) {
|
||||||
|
clickConfirmButton(newRoot)
|
||||||
|
} else {
|
||||||
|
clickCancelButton(newRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("未找到底部选项: $optionText")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 点击确认按钮
|
||||||
|
private fun clickConfirmButton(root: AccessibilityNodeInfo): Boolean {
|
||||||
|
val confirmButton = NodeToolText.findNodeByText(root, "确定")
|
||||||
|
?: NodeToolText.findNodeByText(root, "确认")
|
||||||
|
|
||||||
|
println("查找确认按钮: ${confirmButton != null}")
|
||||||
|
if (confirmButton != null) {
|
||||||
|
println("确认按钮属性 - clickable: ${confirmButton.isClickable}, visibleToUser: ${confirmButton.isVisibleToUser}")
|
||||||
|
if (confirmButton.isClickable) {
|
||||||
|
AccessibilityTool.ensureNodeVisible(confirmButton)
|
||||||
|
AccessibilityTool.performClick(confirmButton)
|
||||||
|
println("已点击确认按钮")
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
println("确认按钮不可点击")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("未找到确认按钮")
|
||||||
|
// 打印当前界面树以便调试
|
||||||
|
AccessibilityTool.printViewTree(root, "确认按钮未找到时的界面树")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击取消按钮
|
||||||
|
private fun clickCancelButton(root: AccessibilityNodeInfo) {
|
||||||
|
val cancelButton = NodeToolText.findNodeByText(root, "取消")
|
||||||
|
if (cancelButton != null && cancelButton.isClickable) {
|
||||||
|
AccessibilityTool.performClick(cancelButton)
|
||||||
|
println("已点击取消按钮")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun expandClassificationSection(root: AccessibilityNodeInfo) {
|
||||||
|
var peopleCountNode = NodeToolText.findNodeByText(root, "请输入人数")
|
||||||
|
if (peopleCountNode == null) {
|
||||||
|
println("未找到员工数输入框")
|
||||||
|
val targetNode = NodeToolText.findNodeByText(root, "分类信息")
|
||||||
|
val nextSibling = NodeToolText.findNextSiblingNode(targetNode)
|
||||||
|
|
||||||
|
if (nextSibling != null && nextSibling.isClickable) {
|
||||||
|
AccessibilityTool.ensureNodeVisible(nextSibling)
|
||||||
|
AccessibilityTool.performClick(nextSibling)
|
||||||
|
Thread.sleep(2000)
|
||||||
|
println("已点击兄弟节点")
|
||||||
|
} else {
|
||||||
|
println("未找到可点击的兄弟节点")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填写集团名称字段
|
||||||
|
* 根据UI树分析,查找hint为"请输入集团名称"的EditText并填入值
|
||||||
|
*/
|
||||||
|
private fun fillGroupNameField(root: AccessibilityNodeInfo, value: String) {
|
||||||
|
fillEditTextByHintText(root,value, "集团名称","请输入集团名称")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fillCompanyNameField(root: AccessibilityNodeInfo, value: String) {
|
||||||
|
fillEditTextByHintText(root,value, "证件名称","证件名称")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fillEditTextByHintText(root: AccessibilityNodeInfo, value: String, fieldName : String, hintText: String) {
|
||||||
|
var editTextNode = NodeToolHint.findNodeByHint(root, hintText)
|
||||||
|
fillEditText(editTextNode,value,fieldName)
|
||||||
|
}
|
||||||
|
private fun fillEditText(editText: AccessibilityNodeInfo?, value: String, fieldName : String) {
|
||||||
|
if (editText == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editText.isEditable) {
|
||||||
|
AccessibilityTool.inputText(editText, value)
|
||||||
|
println("已填写$fieldName: $value")
|
||||||
|
} else {
|
||||||
|
println("未找到${fieldName}输入框或输入框不可编辑")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择集团状态
|
||||||
|
* 根据UI树分析,可以通过点击相关视图来展开选项
|
||||||
|
*/
|
||||||
|
fun selectGroupStatus(root: AccessibilityNodeInfo, status: String = "在网集团") {
|
||||||
|
// 查找包含"在网集团"文本的TextView并点击
|
||||||
|
val statusView = NodeToolText.findNodeByText(root, status)
|
||||||
|
if (statusView != null && statusView.isClickable) {
|
||||||
|
AccessibilityTool.performClick(statusView)
|
||||||
|
println("已选择集团状态: $status")
|
||||||
|
} else {
|
||||||
|
println("未找到集团状态选项或选项不可点击")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择集团等级
|
||||||
|
* 根据UI树分析,可以通过点击相关视图来展开选项
|
||||||
|
*/
|
||||||
|
fun selectGroupLevel(root: AccessibilityNodeInfo, level: String = "D") {
|
||||||
|
// 查找包含"D"文本的TextView并点击
|
||||||
|
val levelView = NodeToolText.findNodeByText(root, level)
|
||||||
|
if (levelView != null && levelView.isClickable) {
|
||||||
|
AccessibilityTool.performClick(levelView)
|
||||||
|
println("已选择集团等级: $level")
|
||||||
|
} else {
|
||||||
|
println("未找到集团等级选项或选项不可点击")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import android.view.accessibility.AccessibilityNodeInfo
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.loveerror.bested.SelectAccessibility
|
import com.loveerror.bested.SelectAccessibility
|
||||||
import com.loveerror.bested.UIInspectorService
|
import com.loveerror.bested.UIInspectorService
|
||||||
|
import com.loveerror.bested.button.ActionEvent
|
||||||
import com.loveerror.bested.tool.AccessibilityTool
|
import com.loveerror.bested.tool.AccessibilityTool
|
||||||
import com.loveerror.bested.tool.NodeToolText
|
import com.loveerror.bested.tool.NodeToolText
|
||||||
|
|
||||||
@@ -19,16 +20,33 @@ class ZjMccmCrm(private val uiInspectorService: UIInspectorService) {
|
|||||||
private var broadcastReceiver: BroadcastReceiver? = null
|
private var broadcastReceiver: BroadcastReceiver? = null
|
||||||
|
|
||||||
fun initialize(context: Context) {
|
fun initialize(context: Context) {
|
||||||
|
|
||||||
|
val listOfActionEvent = listOf(
|
||||||
|
ActionEvent.START_ACTION,
|
||||||
|
ActionEvent.FILL_ACTION,
|
||||||
|
// ActionEvent.SET_DATA_SOURCE,
|
||||||
|
// ActionEvent.HIDE_FLOATING_BUTTON,
|
||||||
|
ActionEvent.PRINT_CURRENT_PAGE
|
||||||
|
)
|
||||||
// 注册广播接收器
|
// 注册广播接收器
|
||||||
broadcastReceiver = object : BroadcastReceiver() {
|
broadcastReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
"com.loveerror.bested.START_ACTION" -> {
|
ActionEvent.START_ACTION.event -> {
|
||||||
// startJob()
|
|
||||||
startJobAsync()
|
startJobAsync()
|
||||||
}
|
}
|
||||||
"com.loveerror.bested.FILL_ACTION" -> {
|
|
||||||
fillAction()
|
ActionEvent.FILL_ACTION.event -> {
|
||||||
|
fillActionAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionEvent.PRINT_CURRENT_PAGE.event -> {
|
||||||
|
AccessibilityTool.printViewTree(uiInspectorService.rootInActiveWindow)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
println("Received unknown action: ${intent.action}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,13 +54,11 @@ class ZjMccmCrm(private val uiInspectorService: UIInspectorService) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val filter = IntentFilter("com.loveerror.bested.START_ACTION")
|
|
||||||
|
|
||||||
registerReceiver(filter, context)
|
|
||||||
|
|
||||||
val filter2 = IntentFilter("com.loveerror.bested.FILL_ACTION")
|
|
||||||
registerReceiver(filter2,context )
|
|
||||||
|
|
||||||
|
listOfActionEvent.forEach {
|
||||||
|
val filter = IntentFilter(it.event)
|
||||||
|
registerReceiver(filter, context)
|
||||||
|
}
|
||||||
|
|
||||||
selectAccessibility = SelectAccessibility(uiInspectorService)
|
selectAccessibility = SelectAccessibility(uiInspectorService)
|
||||||
|
|
||||||
@@ -72,12 +88,16 @@ class ZjMccmCrm(private val uiInspectorService: UIInspectorService) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fillAction() {
|
private fun fillActionAsync() {
|
||||||
val root = rootInActiveWindow()
|
Thread {
|
||||||
if (root == null) {
|
val root = rootInActiveWindow()
|
||||||
return
|
if (root == null) {
|
||||||
}
|
return@Thread
|
||||||
NormalGroupCreateForm.autoFillForm(root)
|
}
|
||||||
|
var normalGroupCreateForm = NormalGroupCreateForm(uiInspectorService)
|
||||||
|
normalGroupCreateForm.autoFillForm(root)
|
||||||
|
}.start()
|
||||||
|
|
||||||
}
|
}
|
||||||
fun someOptEvent(event: AccessibilityEvent?){
|
fun someOptEvent(event: AccessibilityEvent?){
|
||||||
// 获取根节点
|
// 获取根节点
|
||||||
|
|||||||
@@ -76,9 +76,9 @@ class AccessibilityTool {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun performClick(btn: AccessibilityNodeInfo) {
|
fun performClick(btn: AccessibilityNodeInfo, clickParent : Boolean = true) {
|
||||||
android.os.Handler(android.os.Looper.getMainLooper()).post {
|
android.os.Handler(android.os.Looper.getMainLooper()).post {
|
||||||
clickButton(btn)
|
clickButton(btn,clickParent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,13 +95,13 @@ class AccessibilityTool {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clickButton(node: AccessibilityNodeInfo) {
|
fun clickButton(node: AccessibilityNodeInfo, clickParent : Boolean = true) {
|
||||||
if (node.isClickable) {
|
if (node.isClickable) {
|
||||||
node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else if(clickParent){
|
||||||
// 如果节点本身不可点击,尝试查找可点击的父节点
|
// 如果节点本身不可点击,尝试查找可点击的父节点
|
||||||
var parent = node.parent
|
var parent = node.parent
|
||||||
while (parent != null) {
|
while (parent != null) {
|
||||||
|
|||||||
@@ -4,9 +4,69 @@ import android.view.accessibility.AccessibilityNodeInfo
|
|||||||
|
|
||||||
class NodeToolHint {
|
class NodeToolHint {
|
||||||
companion object{
|
companion object{
|
||||||
fun findNodeByHint(node: AccessibilityNodeInfo,vararg targetHints: String): AccessibilityNodeInfo? {
|
|
||||||
return findNodeByHint(node, 0, targetHints.toList())
|
fun findNodeByHint(root: AccessibilityNodeInfo?, targetHint : String) : AccessibilityNodeInfo?{
|
||||||
|
if (root == null) {
|
||||||
|
println("=== targetHint:${targetHint} findNodeByHint Tree Start [root==null] ===")
|
||||||
|
println("=== targetHint:${targetHint} findNodeByHint Tree End [root==null] ===")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
println("=== targetHint:${targetHint} findNodeByHint Tree Start ===")
|
||||||
|
val node = findNodeByHint(root, 0, targetHint)
|
||||||
|
println("=== targetHint:${targetHint} findNodeByHint Tree End ===")
|
||||||
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findNodeByHint(node: AccessibilityNodeInfo, depth: Int, targetHint : String) : AccessibilityNodeInfo?{
|
||||||
|
val indent = " ".repeat(depth)
|
||||||
|
val nodeInfo = "${node.className?.toString() ?: "Unknown"} " +
|
||||||
|
"[text=${node.text?.toString() ?: ""}] " +
|
||||||
|
"[desc=${node.contentDescription?.toString() ?: ""}] " +
|
||||||
|
"[id=${node.viewIdResourceName ?: ""}] " +
|
||||||
|
"[hint=${node.hintText?.toString() ?: ""}] " +
|
||||||
|
"[clickable=${node.isClickable}] " +
|
||||||
|
"[longClickable=${node.isLongClickable}] " +
|
||||||
|
"[editable=${node.isEditable}] " +
|
||||||
|
"[focusable=${node.isFocusable}] " +
|
||||||
|
"[focus=${node.isFocused}] " +
|
||||||
|
"[selected=${node.isSelected}] " +
|
||||||
|
"[checkable=${node.isCheckable}] " +
|
||||||
|
"[checked=${node.isChecked}] " +
|
||||||
|
"[scrollable=${node.isScrollable}] " +
|
||||||
|
"[visibleToUser=${node.isVisibleToUser}] " +
|
||||||
|
"[password=${node.isPassword}] " +
|
||||||
|
"[multiple=${node.isMultiLine}] " +
|
||||||
|
"[accessibilityFocus=${node.isAccessibilityFocused}] " +
|
||||||
|
"[package=${node.packageName?.toString() ?: ""}] " +
|
||||||
|
"[focused=${node.isFocused}] " +
|
||||||
|
"[enabled=${node.isEnabled}] " +
|
||||||
|
"[focusable=${node.isFocusable}] " +
|
||||||
|
"[accessible=${node.isAccessibilityFocused}] " +
|
||||||
|
"[visible=${node.isVisibleToUser}] " +
|
||||||
|
""
|
||||||
|
|
||||||
|
println("${targetHint} $indent$nodeInfo")
|
||||||
|
if (node.hintText?.toString()?.contains(targetHint) == true) {
|
||||||
|
println("=== targetHint:${targetHint} findNodeByHint Tree End [find] ===")
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归打印子节点
|
||||||
|
for (i in 0 until node.childCount) {
|
||||||
|
val child = node.getChild(i)
|
||||||
|
if (child != null) {
|
||||||
|
val ret =findNodeByHint(child, depth + 1, targetHint)
|
||||||
|
if (ret != null){
|
||||||
|
println("=== targetHint:${targetHint} findNodeByHint Tree End [find] ===")
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
// fun findNodeByHint(node: AccessibilityNodeInfo,vararg targetHints: String): AccessibilityNodeInfo? {
|
||||||
|
// return findNodeByHint(node, 0, targetHints.toList())
|
||||||
|
// }
|
||||||
private fun findNodeByHint(node: AccessibilityNodeInfo, depth: Int, targetHints: List<String>): AccessibilityNodeInfo? {
|
private fun findNodeByHint(node: AccessibilityNodeInfo, depth: Int, targetHints: List<String>): AccessibilityNodeInfo? {
|
||||||
if (targetHints.isEmpty()) return null
|
if (targetHints.isEmpty()) return null
|
||||||
|
|
||||||
@@ -19,7 +79,7 @@ class NodeToolHint {
|
|||||||
if (remainingHints.isEmpty()) {
|
if (remainingHints.isEmpty()) {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
// 如果还有更多层级,继续在子节点中查找
|
// 如果还有更多层级,只在子节点中查找下一级hint
|
||||||
else {
|
else {
|
||||||
// 在子节点中查找下一级hint
|
// 在子节点中查找下一级hint
|
||||||
for (i in 0 until node.childCount) {
|
for (i in 0 until node.childCount) {
|
||||||
@@ -33,7 +93,7 @@ class NodeToolHint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果当前节点不匹配且没有更多层级,在子节点中查找第一级hint
|
// 当前节点不匹配,继续在子节点中查找同一级hint
|
||||||
else {
|
else {
|
||||||
for (i in 0 until node.childCount) {
|
for (i in 0 until node.childCount) {
|
||||||
val child = node.getChild(i)
|
val child = node.getChild(i)
|
||||||
|
|||||||
@@ -5,6 +5,26 @@ import android.view.accessibility.AccessibilityNodeInfo
|
|||||||
class NodeToolText {
|
class NodeToolText {
|
||||||
companion object{
|
companion object{
|
||||||
|
|
||||||
|
// 添加一个新的辅助方法来查找兄弟节点
|
||||||
|
fun findNextSiblingNode(node: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
|
||||||
|
if (node == null || node.parent == null) return null
|
||||||
|
|
||||||
|
val parent = node.parent
|
||||||
|
val childCount = parent.childCount
|
||||||
|
var found = false
|
||||||
|
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
val child = parent.getChild(i)
|
||||||
|
if (found && child != null) {
|
||||||
|
return child // 返回找到的第一个兄弟节点
|
||||||
|
}
|
||||||
|
if (child == node) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null // 没有找到兄弟节点
|
||||||
|
}
|
||||||
fun findNodeByText(node: AccessibilityNodeInfo,vararg targetTexts: String): AccessibilityNodeInfo? {
|
fun findNodeByText(node: AccessibilityNodeInfo,vararg targetTexts: String): AccessibilityNodeInfo? {
|
||||||
return findNodeByText(node, 0, targetTexts.toList())
|
return findNodeByText(node, 0, targetTexts.toList())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user