Compare commits
2 Commits
5158cfb83d
...
7506144410
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7506144410 | ||
|
|
16b5efb3c6 |
@@ -10,8 +10,11 @@ enum class ActionEvent {
|
||||
|
||||
QUERY_COMPANY_REGISTER("com.loveerror.bested.QUERY_COMPANY_REGISTER", "去全网查询",isDisplay = true),
|
||||
QUERY_COMPANY_SEARCH_ACTION("com.loveerror.bested.QUERY_COMPANY_SEARCH_ACTION", "查询公司是否注册",isDisplay = true, menuWithText = listOf("companyNames")),
|
||||
|
||||
COORDINATE_CLICK("coordinate_click", "坐标点击", true),
|
||||
UNKNOWN("com.loveerror.bested.UNKNOWN", "未知",isDisplay = false, enable = false);
|
||||
|
||||
|
||||
constructor(event: String, menuName: String, isDisplay: Boolean = true, menuWithText: List<String> = emptyList(), enable: Boolean = true){
|
||||
this.event = event
|
||||
this.menuName = menuName
|
||||
|
||||
@@ -14,6 +14,9 @@ import android.widget.PopupMenu
|
||||
import android.app.Activity
|
||||
import android.content.ContextWrapper
|
||||
import android.widget.LinearLayout
|
||||
import com.loveerror.bested.tool.CoordinateClickTool
|
||||
import com.loveerror.bested.tool.CoordinateListener
|
||||
import com.loveerror.bested.tool.CoordinateListenerImpl
|
||||
|
||||
class DragFloatingButton(context: Context) : View(context) {
|
||||
private val paint = Paint().apply {
|
||||
@@ -66,6 +69,7 @@ class DragFloatingButton(context: Context) : View(context) {
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
startX = event.rawX
|
||||
@@ -116,8 +120,19 @@ class DragFloatingButton(context: Context) : View(context) {
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
|
||||
// 只在特定条件下移除覆盖层
|
||||
if (!isDragging) {
|
||||
// 点击事件 - 显示菜单
|
||||
|
||||
|
||||
val intent = android.content.Intent(ActionEvent.COORDINATE_CLICK.event).apply {
|
||||
setPackage(context.packageName)
|
||||
}
|
||||
val coordinateListenerImpl =
|
||||
CoordinateListenerImpl(event.x, event.y, intent, context = context)
|
||||
|
||||
coordinateClickTool.disableCoordinateClickMode(coordinateListener = coordinateListenerImpl)
|
||||
|
||||
showPopupMenu()
|
||||
}
|
||||
}
|
||||
@@ -125,6 +140,13 @@ class DragFloatingButton(context: Context) : View(context) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 使用新的 CoordinateClickTool
|
||||
private val coordinateClickTool = CoordinateClickTool(context, windowManager)
|
||||
|
||||
|
||||
|
||||
private fun showPopupMenu() {
|
||||
val popup = PopupMenu(context, this)
|
||||
// 添加菜单项 use ActionEvent
|
||||
@@ -261,14 +283,21 @@ class DragFloatingButton(context: Context) : View(context) {
|
||||
|
||||
private fun triggerActionEvent(actionEvent: ActionEvent, textInputs: MutableList<TextWithTag> = mutableListOf()) {
|
||||
try {
|
||||
val intent = android.content.Intent(actionEvent.event).apply {
|
||||
setPackage(context.packageName)
|
||||
when (actionEvent) {
|
||||
ActionEvent.COORDINATE_CLICK -> {
|
||||
coordinateClickTool.enableCoordinateClickMode()
|
||||
}
|
||||
else -> {
|
||||
val intent = android.content.Intent(actionEvent.event).apply {
|
||||
setPackage(context.packageName)
|
||||
}
|
||||
// 如果有文本输入,添加到Intent中
|
||||
for(textWithTag in textInputs){
|
||||
intent.putExtra(textWithTag.tag, textWithTag.text)
|
||||
}
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
// 如果有文本输入,添加到Intent中
|
||||
for(textWithTag in textInputs){
|
||||
intent.putExtra(textWithTag.tag, textWithTag.text)
|
||||
}
|
||||
context.sendBroadcast(intent)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
println("枚举值不存在: $actionEvent, ${e.toString()}")
|
||||
|
||||
@@ -5,16 +5,25 @@ class FieldName {
|
||||
val defaultValue: String
|
||||
val type: FieldType
|
||||
|
||||
constructor(fieldName: String, hintText: String, defaultValue: String, type: FieldType = FieldType.TEXT){
|
||||
val fieldFindBy: FieldFindBy
|
||||
|
||||
constructor(fieldName: String, hintText: String, defaultValue: String, type: FieldType = FieldType.TEXT, fieldFindBy: FieldFindBy = FieldFindBy.HINT){
|
||||
this.fieldName = fieldName
|
||||
this.hintText = hintText
|
||||
this.defaultValue = defaultValue
|
||||
this.type = type
|
||||
this.fieldFindBy = fieldFindBy
|
||||
}
|
||||
val fieldName: String
|
||||
val hintText: String
|
||||
}
|
||||
|
||||
enum class FieldFindBy {
|
||||
TEXT,
|
||||
HINT,
|
||||
CONTENT_DESCRIPTION
|
||||
}
|
||||
|
||||
enum class FieldType {
|
||||
TEXT,
|
||||
SELECT,
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.loveerror.bested.tool.RootNodeCallback
|
||||
|
||||
class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
|
||||
fun getRootInActiveWindow(): AccessibilityNodeInfo? {
|
||||
fun getRootInActiveWindow(): AccessibilityNodeInfo {
|
||||
return rootNodeCallback.getRootNodeReceived()
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
fields.add(FieldName("法人代表", "请输入法人姓名", "", FieldType.TEXT))
|
||||
fields.add(FieldName("证件地址", "请输入证件地址", "", FieldType.TEXT))
|
||||
fields.add(FieldName("联系电话", "请输入联系电话", "13266667777", FieldType.TEXT))
|
||||
fields.add(FieldName("员工数", "请输入人数", "1", FieldType.TEXT))
|
||||
fields.add(FieldName("员工数", "请输入人数", "1", FieldType.TEXT, fieldFindBy= FieldFindBy.TEXT))
|
||||
|
||||
// select
|
||||
fields.add(FieldName("集团状态", "", "潜在集团", FieldType.SELECT))
|
||||
@@ -54,9 +54,17 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
convertedMap[mappedKey] = value
|
||||
}
|
||||
convertedMap["证件名称"]= convertedMap["集团名称"].toString()
|
||||
|
||||
// 参保人数值如果为 eg: 8人 ->8
|
||||
if (convertedMap["员工数"]?.contains("人") == true) {
|
||||
convertedMap["员工数"] = convertedMap["员工数"]?.replace("人", "").toString()
|
||||
// 处理 "2人 (2024年报)" 格式,提取数字部分
|
||||
val regex = Regex("(\\d+)人")
|
||||
val matchResult = regex.find(convertedMap["员工数"].toString())
|
||||
if (matchResult != null) {
|
||||
convertedMap["员工数"] = matchResult.groupValues[1]
|
||||
} else {
|
||||
convertedMap["员工数"] = convertedMap["员工数"]?.replace("人", "").toString()
|
||||
}
|
||||
}
|
||||
return convertedMap
|
||||
}
|
||||
@@ -147,10 +155,16 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
field.hintText, fieldMap[field.fieldName] ?: field.defaultValue
|
||||
)
|
||||
} else {
|
||||
AccessibilityTool.fillEditTextByHintText(
|
||||
root, fieldMap[field.fieldName] ?: field.defaultValue, field.fieldName,
|
||||
field.hintText
|
||||
)
|
||||
if (field.fieldFindBy == FieldFindBy.TEXT) {
|
||||
AccessibilityTool.fillEditTextByText(root, fieldMap[field.fieldName] ?: field.defaultValue, field.fieldName,
|
||||
field.hintText)
|
||||
}else{
|
||||
AccessibilityTool.fillEditTextByHintText(
|
||||
root, fieldMap[field.fieldName] ?: field.defaultValue, field.fieldName,
|
||||
field.hintText
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,11 +199,11 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
AccessibilityTool.fillEditText(peopleCountNode, fieldMap["员工数"] ?: "1", "员工数")
|
||||
// fillEditTextByHintText(rootNew,fieldMap["员工数"] ?: "1", "员工数", "请输入人数")
|
||||
|
||||
// clickToOpenBottomSheetAddress(
|
||||
// root,
|
||||
// "请点击此处打点",
|
||||
// "浙江省杭州市余杭区高顺路8号五常西溪软件园金牛座A座"
|
||||
// )
|
||||
clickToOpenBottomSheetAddress(
|
||||
rootNodeCallback.getRootNodeReceived(),
|
||||
"请点击此处打点",
|
||||
"浙江省杭州市余杭区高顺路8号五常西溪软件园金牛座A座"
|
||||
)
|
||||
// 示例:点击"集团状态"触发底部选择,选择"在网集团"
|
||||
// fillCompanyNameField(root, groupName)
|
||||
|
||||
@@ -204,7 +218,7 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
address: String
|
||||
) {
|
||||
//
|
||||
val triggerNode = NodeToolText.findNodeByText(root, triggerText)
|
||||
val triggerNode = NodeToolText.findNodeByText(rootNodeCallback.getRootNodeReceived(), triggerText)
|
||||
|
||||
// 父级的可点击
|
||||
if (triggerNode != null) {
|
||||
@@ -219,9 +233,9 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
return
|
||||
}
|
||||
|
||||
Thread.sleep(3000)
|
||||
Thread.sleep(8000)
|
||||
// 地图选址 按钮
|
||||
val mapSearchButton = NodeToolText.findNodeByText(getRootInActiveWindow(), "地图选址")
|
||||
val mapSearchButton = NodeToolText.findNodeByText(rootNodeCallback.getRootNodeReceived(), "地图选址")
|
||||
if (mapSearchButton != null) {
|
||||
AccessibilityTool.performClick(mapSearchButton)
|
||||
println("已点击地图选址按钮")
|
||||
@@ -229,14 +243,14 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
println("未找到地图选址按钮")
|
||||
return
|
||||
}
|
||||
Thread.sleep(3000)
|
||||
Thread.sleep(5000)
|
||||
var clickFirst = findTargetElement(getRootInActiveWindow())
|
||||
if (clickFirst == null) {
|
||||
println("clickFirst is null")
|
||||
return
|
||||
}
|
||||
AccessibilityTool.performClick(clickFirst)
|
||||
Thread.sleep(3000)
|
||||
Thread.sleep(5000)
|
||||
|
||||
var searchButton = NodeToolText.findNodeByText(getRootInActiveWindow(), "搜索")
|
||||
if (searchButton == null) {
|
||||
@@ -337,7 +351,7 @@ class NormalGroupCreateForm(private val rootNodeCallback: RootNodeCallback) {
|
||||
}
|
||||
|
||||
private fun checkTextViewWithRetry(): Boolean {
|
||||
repeat(5) {
|
||||
repeat(15) {
|
||||
val textView = NodeToolText.findNodeByText(getRootInActiveWindow(), "宽带选址")
|
||||
if (textView != null && textView.viewIdResourceName == "com.ZJMCCMCRM:id/title") {
|
||||
return true // 找到匹配的控件
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.loveerror.bested.SelectAccessibility
|
||||
import com.loveerror.bested.button.ActionEvent
|
||||
import com.loveerror.bested.button.DragFloatingButton
|
||||
import com.loveerror.bested.tool.AccessibilityTool
|
||||
import com.loveerror.bested.tool.GestureTool
|
||||
import com.loveerror.bested.tool.NodeToolText
|
||||
import com.loveerror.bested.tool.RootNodeCallback
|
||||
|
||||
@@ -21,6 +22,7 @@ class ZjMccmCrm(private val rootNodeCallback: RootNodeCallback) {
|
||||
private lateinit var selectAccessibility: SelectAccessibility
|
||||
private var broadcastReceiver: BroadcastReceiver? = null
|
||||
|
||||
private val gestureTool: GestureTool = GestureTool(rootNodeCallback)
|
||||
fun initialize(context: Context) {
|
||||
|
||||
val listOfActionEvent = ActionEvent.entries.filter { it.enable }
|
||||
@@ -60,6 +62,12 @@ class ZjMccmCrm(private val rootNodeCallback: RootNodeCallback) {
|
||||
searchCompanyActionAsync(intent,floatingButton)
|
||||
}
|
||||
|
||||
ActionEvent.COORDINATE_CLICK.event -> {
|
||||
val x = intent.getFloatExtra("x", 0f)
|
||||
val y = intent.getFloatExtra("y", 0f)
|
||||
gestureTool.performGestureClick(x, y)
|
||||
}
|
||||
|
||||
else -> {
|
||||
println("Received unknown action: ${intent.action}")
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ class AccessibilityTool {
|
||||
fillEditText(editTextNode,value,fieldName)
|
||||
}
|
||||
|
||||
fun fillEditTextByText(root: AccessibilityNodeInfo, value: String, fieldName : String, hintText: String) {
|
||||
val editTextNode = NodeToolText.findNodeByText(root, hintText)
|
||||
fillEditText(editTextNode,value,fieldName)
|
||||
}
|
||||
|
||||
fun fillEditText(editText: AccessibilityNodeInfo?, value: String, fieldName : String) {
|
||||
if (editText == null) {
|
||||
return
|
||||
@@ -84,7 +89,7 @@ class AccessibilityTool {
|
||||
println("已选择第一个搜索结果")
|
||||
|
||||
// 点击确认按钮
|
||||
Thread.sleep(500)
|
||||
Thread.sleep(3000)
|
||||
val confirmButton = NodeToolText.findNodeByText(root, "确认")
|
||||
?: NodeToolText.findNodeByText(root, "确定")
|
||||
if (confirmButton?.isClickable == true) {
|
||||
@@ -113,7 +118,7 @@ class AccessibilityTool {
|
||||
clickToOpenBottomSheet(rootNodeCallback.getRootNodeReceived(), fieldName)
|
||||
|
||||
// 2. 等待对话框完全显示
|
||||
Thread.sleep(1000)
|
||||
Thread.sleep(5000)
|
||||
|
||||
NodeToolTime.selectDateWithRetry(rootNodeCallback, year, month, day)
|
||||
}
|
||||
@@ -136,22 +141,18 @@ class AccessibilityTool {
|
||||
}
|
||||
|
||||
fun performBottomSheetSelection(rootNodeCallback: RootNodeCallback, triggerText: String, optionText: String) {
|
||||
val root = rootNodeCallback.getRootNodeReceived()
|
||||
if(root == null){
|
||||
return
|
||||
}
|
||||
// 1. 点击触发元素打开底部对话框
|
||||
clickToOpenBottomSheet(root, triggerText)
|
||||
clickToOpenBottomSheet(rootNodeCallback.getRootNodeReceived(), triggerText)
|
||||
|
||||
// 2. 等待对话框完全显示
|
||||
Thread.sleep(1000)
|
||||
Thread.sleep(4000)
|
||||
|
||||
// 3. 选择目标选项
|
||||
selectOptionFromBottomSheet(rootNodeCallback,optionText)
|
||||
|
||||
// 4. 明确点击确认按钮 dubbo check
|
||||
clickConfirmButton(rootNodeCallback)
|
||||
Thread.sleep(500) // 等待确认操作完成
|
||||
Thread.sleep(1500) // 等待确认操作完成
|
||||
}
|
||||
|
||||
// 点击可点击的触发元素来显示底部选择对话框
|
||||
@@ -182,9 +183,6 @@ class AccessibilityTool {
|
||||
fun selectOptionFromBottomSheet(rootNodeCallback: RootNodeCallback,optionText: String, confirm: Boolean = true) {
|
||||
// 获取更新后的根节点
|
||||
val newRoot = rootNodeCallback.getRootNodeReceived()
|
||||
if (newRoot == null) {
|
||||
return
|
||||
}
|
||||
|
||||
// 查找并点击选项
|
||||
val optionNode = NodeToolText.findNodeByText(newRoot, optionText)
|
||||
@@ -204,6 +202,7 @@ class AccessibilityTool {
|
||||
} else {
|
||||
println("未找到底部选项: $optionText")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// CoordinateClickTool.kt
|
||||
package com.loveerror.bested.tool
|
||||
|
||||
import android.content.Context
|
||||
import android.view.WindowManager
|
||||
interface CoordinateListener {
|
||||
fun onDisable()
|
||||
}
|
||||
|
||||
class CoordinateListenerImpl(private val x: Float,private val y: Float,private val intent: android.content.Intent,private val context: Context): CoordinateListener {
|
||||
|
||||
override fun onDisable() {
|
||||
|
||||
intent.putExtra("x",x)
|
||||
intent.putExtra("y",y)
|
||||
context.sendBroadcast(intent)
|
||||
return
|
||||
}
|
||||
}
|
||||
class CoordinateClickTool(private val context: Context, private val windowManager: WindowManager) {
|
||||
|
||||
private var isCoordinateClickMode = false
|
||||
private val overlayTool = OverlayTool(context, windowManager)
|
||||
|
||||
fun isCoordinateClickMode(): Boolean {
|
||||
return isCoordinateClickMode
|
||||
}
|
||||
|
||||
fun enableCoordinateClickMode() {
|
||||
isCoordinateClickMode = true
|
||||
if (!overlayTool.isOverlayVisible()) {
|
||||
overlayTool.createOverlayView()
|
||||
}
|
||||
}
|
||||
|
||||
fun disableCoordinateClickMode(coordinateListener: CoordinateListener? = null) {
|
||||
val canSend = isCoordinateClickMode
|
||||
|
||||
isCoordinateClickMode = false
|
||||
overlayTool.removeOverlayView()
|
||||
|
||||
if(canSend){
|
||||
coordinateListener?.onDisable()
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleCoordinateClickMode() {
|
||||
if (isCoordinateClickMode) {
|
||||
disableCoordinateClickMode()
|
||||
} else {
|
||||
enableCoordinateClickMode()
|
||||
}
|
||||
}
|
||||
|
||||
// fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
//
|
||||
// when (event.action) {
|
||||
//
|
||||
// MotionEvent.ACTION_UP -> {
|
||||
// if(!isCoordinateClickMode){
|
||||
// // 非拖拽且非坐标点击模式下移除覆盖层
|
||||
// overlayTool.removeOverlayView()
|
||||
// isCoordinateClickMode = false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return true
|
||||
// }
|
||||
}
|
||||
76
app/src/main/java/com/loveerror/bested/tool/GestureTool.kt
Normal file
76
app/src/main/java/com/loveerror/bested/tool/GestureTool.kt
Normal file
@@ -0,0 +1,76 @@
|
||||
package com.loveerror.bested.tool
|
||||
|
||||
import android.accessibilityservice.GestureDescription
|
||||
import android.graphics.Path
|
||||
import android.os.Build
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import com.loveerror.bested.UIInspectorService
|
||||
|
||||
class GestureTool (private val rootNodeCallback: RootNodeCallback){
|
||||
/**
|
||||
* 根据屏幕坐标执行点击操作
|
||||
* @param x X坐标
|
||||
* @param y Y坐标
|
||||
* @param rootNodeCallback 根节点回调接口
|
||||
*/
|
||||
fun performClickAtCoordinates(x: Float, y: Float) {
|
||||
// 可以通过手势模拟实现坐标点击
|
||||
performGestureClick(x, y)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过系统手势API执行坐标点击
|
||||
* @param x X坐标
|
||||
* @param y Y坐标
|
||||
* @param rootNodeCallback 根节点回调接口
|
||||
*/
|
||||
fun performGestureClick(x: Float, y: Float) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
// 使用手势API实现点击
|
||||
// 这里需要获取AccessibilityService实例来执行手势
|
||||
// 实现细节取决于具体如何获取AccessibilityService
|
||||
// 需要通过AccessibilityService执行手势点击
|
||||
rootNodeCallback.performGestureClick(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定节点区域内执行相对坐标点击
|
||||
* @param node 目标节点
|
||||
* @param relativeX 相对于节点的X偏移
|
||||
* @param relativeY 相对于节点的Y偏移
|
||||
*/
|
||||
fun performClickInNode(node: AccessibilityNodeInfo, relativeX: Int, relativeY: Int) {
|
||||
val bounds = android.graphics.Rect()
|
||||
node.getBoundsInScreen(bounds)
|
||||
|
||||
val clickX = bounds.left + relativeX
|
||||
val clickY = bounds.top + relativeY
|
||||
|
||||
// 需要通过AccessibilityService执行手势点击
|
||||
// 这里只是一个概念性实现,实际需要获取AccessibilityService实例
|
||||
// 需要通过AccessibilityService执行手势点击
|
||||
performGestureClick(clickX.toFloat(), clickY.toFloat())
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击节点下方指定偏移位置
|
||||
* @param node 目标节点
|
||||
* @param offsetDp 向下偏移的dp值
|
||||
*/
|
||||
fun clickBelowNode(node: AccessibilityNodeInfo, offsetDp: Float = 25f) {
|
||||
val bounds = android.graphics.Rect()
|
||||
node.getBoundsInScreen(bounds)
|
||||
|
||||
// 将dp转换为像素
|
||||
val density = android.content.res.Resources.getSystem().displayMetrics.density
|
||||
val pixelOffset = (offsetDp * density).toInt()
|
||||
|
||||
// 计算点击坐标(节点底部中心位置向下偏移)
|
||||
val clickX = bounds.centerX()
|
||||
val clickY = bounds.bottom + pixelOffset
|
||||
|
||||
// 需要通过AccessibilityService执行手势点击
|
||||
performGestureClick(clickX.toFloat(), clickY.toFloat())
|
||||
}
|
||||
}
|
||||
90
app/src/main/java/com/loveerror/bested/tool/OverlayTool.kt
Normal file
90
app/src/main/java/com/loveerror/bested/tool/OverlayTool.kt
Normal file
@@ -0,0 +1,90 @@
|
||||
package com.loveerror.bested.tool
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.PixelFormat
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
|
||||
// 创建新的 OverlayTool 类
|
||||
class OverlayTool(private val context: Context, private val windowManager: WindowManager) {
|
||||
|
||||
private var overlayView: View? = null
|
||||
|
||||
// 创建半透明覆盖层的方法
|
||||
fun createOverlayView(): View {
|
||||
return View(context).apply {
|
||||
// 设置半透明背景
|
||||
setBackgroundColor(Color.argb(128, 0, 0, 0)) // 50%透明度的黑色
|
||||
|
||||
// 设置布局参数
|
||||
val overlayParams = WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||
PixelFormat.TRANSLUCENT
|
||||
)
|
||||
|
||||
// 添加到窗口管理器
|
||||
windowManager.addView(this, overlayParams)
|
||||
|
||||
|
||||
this.setOnTouchListener { v, event ->
|
||||
removeOverlayView()
|
||||
// 显示坐标弹窗
|
||||
showCoordinateDialog(event.rawX, event.rawY)
|
||||
return@setOnTouchListener false }
|
||||
|
||||
overlayView = this
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun showCoordinateDialog(x: Float, y: Float) {
|
||||
val message = "点击坐标:\nX: $x\nY: $y"
|
||||
val dialog = AlertDialog.Builder(context)
|
||||
.setTitle("坐标信息")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("确定", null)
|
||||
.create();
|
||||
|
||||
// .show()
|
||||
// 设置对话框类型为系统级对话框
|
||||
val window = dialog.window
|
||||
window?.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
|
||||
|
||||
// 在对话框关闭后移除覆盖层
|
||||
dialog.setOnCancelListener {
|
||||
// isCoordinateClickMode = false
|
||||
// removeOverlayView()
|
||||
}
|
||||
dialog.setOnDismissListener {
|
||||
// isCoordinateClickMode = false
|
||||
// removeOverlayView()
|
||||
}
|
||||
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
// 移除覆盖层的方法
|
||||
fun removeOverlayView() {
|
||||
println("Attempting to remove overlay view, current overlayView: $overlayView")
|
||||
overlayView?.let { view ->
|
||||
try {
|
||||
windowManager.removeView(view)
|
||||
println("Overlay view removed successfully")
|
||||
} catch (e: Exception) {
|
||||
println("Error removing overlay view: ${e.message}")
|
||||
}
|
||||
overlayView = null
|
||||
} ?: println("No overlay view to remove")
|
||||
}
|
||||
|
||||
// 检查覆盖层是否存在
|
||||
fun isOverlayVisible(): Boolean {
|
||||
return overlayView != null
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
package com.loveerror.bested.tool
|
||||
|
||||
import android.accessibilityservice.GestureDescription
|
||||
import android.graphics.Path
|
||||
import android.os.Build
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import com.loveerror.bested.UIInspectorService
|
||||
|
||||
fun interface RootNodeCallback {
|
||||
interface RootNodeCallback {
|
||||
fun getRootNodeReceived(): AccessibilityNodeInfo
|
||||
|
||||
fun performGestureClick(x: Float, y: Float)
|
||||
}
|
||||
|
||||
class RootNodeCallbackImpl(private var uiInspectorService: UIInspectorService) : RootNodeCallback {
|
||||
@@ -12,4 +17,26 @@ class RootNodeCallbackImpl(private var uiInspectorService: UIInspectorService) :
|
||||
override fun getRootNodeReceived(): AccessibilityNodeInfo {
|
||||
return uiInspectorService.rootInActiveWindow
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过系统手势API执行坐标点击
|
||||
* @param x X坐标
|
||||
* @param y Y坐标
|
||||
*/
|
||||
override fun performGestureClick(x: Float, y: Float) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
try {
|
||||
val path = Path()
|
||||
path.moveTo(x, y)
|
||||
|
||||
val gestureBuilder = GestureDescription.Builder()
|
||||
gestureBuilder.addStroke(GestureDescription.StrokeDescription(path, 0, 50))
|
||||
|
||||
val gesture = gestureBuilder.build()
|
||||
uiInspectorService.dispatchGesture(gesture, null, null)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user