diff --git a/app/src/main/java/com/loveerror/bested/button/ActionEvent.kt b/app/src/main/java/com/loveerror/bested/button/ActionEvent.kt index a96ce35..f73b4f4 100644 --- a/app/src/main/java/com/loveerror/bested/button/ActionEvent.kt +++ b/app/src/main/java/com/loveerror/bested/button/ActionEvent.kt @@ -11,7 +11,10 @@ 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), + COORDINATE_CLICK("coordinate_click", "获取坐标位置", true), + + COORDINATE_CLICK_TEST("coordinate_click_test", "坐标点击测试", true, menuWithText = listOf("x", "y")), + UNKNOWN("com.loveerror.bested.UNKNOWN", "未知",isDisplay = false, enable = false); @@ -40,5 +43,10 @@ enum class ActionEvent { } return UNKNOWN } + + // 新增辅助方法判断是否为打印当前页面事件 + fun isPrintCurrentPage(event: ActionEvent): Boolean { + return event == PRINT_CURRENT_PAGE + } } } \ No newline at end of file diff --git a/app/src/main/java/com/loveerror/bested/button/DragFloatingButton.kt b/app/src/main/java/com/loveerror/bested/button/DragFloatingButton.kt index 4cd40fd..65d8ae6 100644 --- a/app/src/main/java/com/loveerror/bested/button/DragFloatingButton.kt +++ b/app/src/main/java/com/loveerror/bested/button/DragFloatingButton.kt @@ -13,12 +13,21 @@ import android.widget.EditText import android.widget.PopupMenu import android.app.Activity import android.content.ContextWrapper +import android.content.Intent +import android.content.IntentFilter +import android.os.Build import android.widget.LinearLayout +import androidx.core.content.ContextCompat import com.loveerror.bested.tool.CoordinateClickTool -import com.loveerror.bested.tool.CoordinateListener import com.loveerror.bested.tool.CoordinateListenerImpl +import com.loveerror.bested.tool.SystemTool class DragFloatingButton(context: Context) : View(context) { + + // 添加坐标存储变量 + private var lastClickX: Float = 0f + private var lastClickY: Float = 0f + private val paint = Paint().apply { isAntiAlias = true style = Paint.Style.FILL @@ -32,6 +41,9 @@ class DragFloatingButton(context: Context) : View(context) { private var originalY = 0 private var isDragging = false + // 在 DragFloatingButton.kt 中添加成员变量 + private var dialogBroadcastReceiver: android.content.BroadcastReceiver? = null + init { // 初始化时创建正确的 WindowManager.LayoutParams this.layoutParams = WindowManager.LayoutParams( @@ -40,8 +52,93 @@ class DragFloatingButton(context: Context) : View(context) { WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT ) + + // 注册用于接收显示弹窗请求的广播 + registerDialogReceiver() } + // 添加注册广播接收器的方法 + private fun registerDialogReceiver() { + dialogBroadcastReceiver = object : android.content.BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + "com.loveerror.bested.SHOW_VIEW_TREE_DIALOG" -> { + val viewTreeData = intent.getStringExtra("view_tree_data") ?: "" + showViewTreeDialog(viewTreeData) + } + } + } + } + + val filter = IntentFilter("com.loveerror.bested.SHOW_VIEW_TREE_DIALOG") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.registerReceiver(dialogBroadcastReceiver, filter, Context.RECEIVER_NOT_EXPORTED) + } else { + ContextCompat.registerReceiver( + context, + dialogBroadcastReceiver, + filter, + ContextCompat.RECEIVER_NOT_EXPORTED + ) + } + } + + // 添加清理方法 + fun cleanup() { + dialogBroadcastReceiver?.let { + try { + context.unregisterReceiver(it) + } catch (e: Exception) { + // 忽略异常 + } + } + } + + // 添加显示弹窗的方法 + private fun showViewTreeDialog(data: String) { +// (context as? Activity)?.runOnUiThread { +// +// } + try { + val dialogBuilder = AlertDialog.Builder(context) + val editText = EditText(context).apply { + setText(data) + setTextIsSelectable(true) + movementMethod = ScrollingMovementMethod.getInstance() + setLines(15) + gravity = Gravity.TOP or Gravity.START + setBackgroundColor(Color.parseColor("#F0F0F0")) + } + + val container = LinearLayout(context).apply { + orientation = LinearLayout.VERTICAL + setPadding(20, 20, 20, 20) + addView(editText) + } + + val dialog = dialogBuilder + .setTitle("界面数据") + .setView(container) + .setPositiveButton("复制") { _, _ -> + SystemTool.copyToClipboard(context, data) + } + .setNegativeButton("关闭", null) + .create() + // + //.show() + + // 设置对话框类型为系统级对话框 + val window = dialog.window + window?.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY) + + dialog.show() + } catch (e: Exception) { + e.printStackTrace() + } + } + + + override fun onDraw(canvas: Canvas) { super.onDraw(canvas) @@ -72,9 +169,16 @@ class DragFloatingButton(context: Context) : View(context) { when (event.action) { MotionEvent.ACTION_DOWN -> { + + + startX = event.rawX startY = event.rawY + // 记录点击坐标 + lastClickX = startX + lastClickY = startY + // 确保 layoutParams 是 WindowManager.LayoutParams 类型 if (this.layoutParams is WindowManager.LayoutParams) { layoutParams = this.layoutParams as WindowManager.LayoutParams @@ -124,12 +228,17 @@ class DragFloatingButton(context: Context) : View(context) { // 只在特定条件下移除覆盖层 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) + CoordinateListenerImpl(event.x, event.y, intent, context = context, callback = fun(x: Float,y: Float){ + // 记录点击坐标 + lastClickX = x + lastClickY = y + }) coordinateClickTool.disableCoordinateClickMode(coordinateListener = coordinateListenerImpl) @@ -146,16 +255,26 @@ class DragFloatingButton(context: Context) : View(context) { private val coordinateClickTool = CoordinateClickTool(context, windowManager) + class FieldNameValue { + var name: String = "" + var value: String = "" + } private fun showPopupMenu() { val popup = PopupMenu(context, this) // 添加菜单项 use ActionEvent for (item in ActionEvent.entries){ if (item.isDisplay) { + val fieldNameValues = ArrayList() + if(item == ActionEvent.COORDINATE_CLICK_TEST){ + // default x,y value use lastClickX,lastClickY + fieldNameValues.add(FieldNameValue().apply {name="x";value=lastClickX.toString()}) + fieldNameValues.add(FieldNameValue().apply {name="y";value=lastClickY.toString()}) + } // 检查是否需要文本输入 if (item.menuWithText.isNotEmpty()) { popup.menu.add(0, item.ordinal, 0, item.menuName).setOnMenuItemClickListener { - showTextInputDialog(item) + showTextInputDialog(item, fieldNameValues) true } } else { @@ -177,7 +296,13 @@ class DragFloatingButton(context: Context) : View(context) { } - private fun showTextInputDialog(actionEvent: ActionEvent) { + private fun showTextInputDialog( + actionEvent: ActionEvent, + fieldNameValues: ArrayList + ) { + // fieldNameValues 转成key value形式的map + + val fieldNameValuesMap = fieldNameValues.associate { it.name to it.value } println("Attempting to show text input dialog for: ${actionEvent.menuName}") // 根据 actionEvent.menuWithText 创建对应数量的editText 放到一个 linearLayout 中 val editTexts = arrayListOf() @@ -200,6 +325,8 @@ class DragFloatingButton(context: Context) : View(context) { hint = menuWithText tag = menuWithText + val fieldNameValue = fieldNameValuesMap[menuWithText] + setText(fieldNameValue?:"") // 添加双击全选支持 var lastClickTime = 0L val doubleClickThreshold = 300L // 双击时间阈值(毫秒) @@ -287,6 +414,29 @@ class DragFloatingButton(context: Context) : View(context) { ActionEvent.COORDINATE_CLICK -> { coordinateClickTool.enableCoordinateClickMode() } + ActionEvent.COORDINATE_CLICK_TEST -> { + // 解析坐标参数 + var xCoord = 0f + var yCoord = 0f + + for (textWithTag in textInputs) { + when (textWithTag.tag) { + "x" -> xCoord = textWithTag.text.toFloatOrNull() ?: 0f + "y" -> yCoord = textWithTag.text.toFloatOrNull() ?: 0f + } + } + + // 创建坐标监听器并执行点击 + val intent = android.content.Intent(actionEvent.event).apply { + setPackage(context.packageName) + } + + val coordinateListener = CoordinateListenerImpl(xCoord, yCoord, intent, context = context) + coordinateClickTool.disableCoordinateClickMode(coordinateListener = coordinateListener) + + context.sendBroadcast(intent) + + } else -> { val intent = android.content.Intent(actionEvent.event).apply { setPackage(context.packageName) diff --git a/app/src/main/java/com/loveerror/bested/handler/ZJMCCMCRM.kt b/app/src/main/java/com/loveerror/bested/handler/ZJMCCMCRM.kt index 7fb8a38..1e4af9d 100644 --- a/app/src/main/java/com/loveerror/bested/handler/ZJMCCMCRM.kt +++ b/app/src/main/java/com/loveerror/bested/handler/ZJMCCMCRM.kt @@ -40,7 +40,16 @@ class ZjMccmCrm(private val rootNodeCallback: RootNodeCallback) { } ActionEvent.PRINT_CURRENT_PAGE.event -> { - AccessibilityTool.printViewTree(rootNodeCallback.getRootNodeReceived()) +// AccessibilityTool.printViewTree(rootNodeCallback.getRootNodeReceived()) + // 修改此处:获取界面数据并发送回 UI 界面显示 + val viewTreeData = AccessibilityTool.getViewTreeAsString(rootNodeCallback.getRootNodeReceived()) + + // 发送广播给 DragFloatingButton 显示弹窗 + val resultIntent = Intent("com.loveerror.bested.SHOW_VIEW_TREE_DIALOG").apply { + putExtra("view_tree_data", viewTreeData) + setPackage(context.packageName) + } + context.sendBroadcast(resultIntent) } ActionEvent.QUERY_COMPANY_REGISTER.event -> { diff --git a/app/src/main/java/com/loveerror/bested/tool/AccessibilityTool.kt b/app/src/main/java/com/loveerror/bested/tool/AccessibilityTool.kt index 9c3a01f..b366121 100644 --- a/app/src/main/java/com/loveerror/bested/tool/AccessibilityTool.kt +++ b/app/src/main/java/com/loveerror/bested/tool/AccessibilityTool.kt @@ -434,6 +434,51 @@ class AccessibilityTool { } } + // 新增返回字符串版本的 printViewTree 方法 + fun getViewTreeAsString(root: AccessibilityNodeInfo?): String { + if (root == null) return "Root node is null" + + val sb = StringBuilder() + printNodeToString(root, 0, sb) + return sb.toString() + } + + // 修改 printNodeToString 方法以包含更多布局信息 + private fun printNodeToString(node: AccessibilityNodeInfo?, depth: Int, sb: StringBuilder) { + if (node == null) return + + val indent = " ".repeat(depth) + sb.append("$indent${node.className}: \"${node.text}\"") + + if (node.contentDescription != null) { + sb.append(" desc:\"${node.contentDescription}\"") + } + + if (node.viewIdResourceName != null) { + sb.append(" id:${node.viewIdResourceName}") + } + + // 添加节点的布局信息 + val bounds = android.graphics.Rect() + node.getBoundsInScreen(bounds) + sb.append(" bounds:[${bounds.left},${bounds.top}][${bounds.right},${bounds.bottom}]") + + // 添加节点的其他重要属性 + sb.append(" clickable:${node.isClickable}") + sb.append(" visible:${node.isVisibleToUser}") + sb.append(" enabled:${node.isEnabled}") + sb.append(" focusable:${node.isFocusable}") + sb.append(" focused:${node.isFocused}") + sb.append(" selected:${node.isSelected}") + sb.append(" scrollable:${node.isScrollable}") + + sb.append("\n") + + for (i in 0 until node.childCount) { + printNodeToString(node.getChild(i), depth + 1, sb) + } + } + fun printViewTree(root: AccessibilityNodeInfo?, pre : String = "") { if (root == null) { println("=== ${pre} View Tree Start [root==null] ===") @@ -471,6 +516,7 @@ class AccessibilityTool { "[focusable=${node.isFocusable}] " + "[accessible=${node.isAccessibilityFocused}] " + "[visible=${node.isVisibleToUser}] " + + "[nodeToString=$node] " + "" println("${pre} $indent$nodeInfo") diff --git a/app/src/main/java/com/loveerror/bested/tool/CoordinateClickTool.kt b/app/src/main/java/com/loveerror/bested/tool/CoordinateClickTool.kt index b753ac6..93d6c4e 100644 --- a/app/src/main/java/com/loveerror/bested/tool/CoordinateClickTool.kt +++ b/app/src/main/java/com/loveerror/bested/tool/CoordinateClickTool.kt @@ -7,13 +7,19 @@ 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 { +fun OtherAction() : Unit { + +} +class CoordinateListenerImpl(private val x: Float,private val y: Float,private val intent: android.content.Intent,private val context: Context, private val callback: ((x: Float,y: Float) -> Unit)? = null): CoordinateListener { override fun onDisable() { intent.putExtra("x",x) intent.putExtra("y",y) context.sendBroadcast(intent) + + // 执行回调函数 + callback?.invoke(x, y) return } } @@ -34,15 +40,19 @@ class CoordinateClickTool(private val context: Context, private val windowManage } fun disableCoordinateClickMode(coordinateListener: CoordinateListener? = null) { - val canSend = isCoordinateClickMode +// val canSend = isCoordinateClickMode isCoordinateClickMode = false overlayTool.removeOverlayView() - if(canSend){ - coordinateListener?.onDisable() - } +// if(canSend){ +// coordinateListener?.onDisable() +// } } + +// fun sendCoordinate(x: Float, y: Float, intent: android.content.Intent, callback: ((x: Float,y: Float) -> Unit)? = null) { +// callback?.invoke(x, y) +// } fun toggleCoordinateClickMode() { if (isCoordinateClickMode) { diff --git a/app/src/main/java/com/loveerror/bested/tool/SystemTool.kt b/app/src/main/java/com/loveerror/bested/tool/SystemTool.kt new file mode 100644 index 0000000..0f326fd --- /dev/null +++ b/app/src/main/java/com/loveerror/bested/tool/SystemTool.kt @@ -0,0 +1,26 @@ +package com.loveerror.bested.tool + +import android.content.Context + +class SystemTool { + companion object{ + fun getCurrentTime(): String { + val currentTime = System.currentTimeMillis() + return currentTime.toString() + } + // 添加复制到剪贴板的方法 + fun copyToClipboard(context: Context,text: String) { + try { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager + val clip = android.content.ClipData.newPlainText("界面数据", text) + clipboard.setPrimaryClip(clip) + + // 显示复制成功提示 + android.widget.Toast.makeText(context, "已复制到剪贴板", android.widget.Toast.LENGTH_SHORT).show() + } catch (e: Exception) { + e.printStackTrace() + android.widget.Toast.makeText(context, "复制失败", android.widget.Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file