Revert "Update .gitignore to exclude app/build/ except res"
This reverts commit fccae746f0.
This commit is contained in:
@@ -1076,13 +1076,6 @@ class MainActivity : AppCompatActivity() {
|
||||
* ✅ 统一的Intent处理方法
|
||||
*/
|
||||
private fun handleIntentAndPermissions(intent: Intent) {
|
||||
// ✅ 安全检查:确保UI组件已初始化(onNewIntent可能在initViews之前被调用)
|
||||
// 直接return,不尝试initViews()——Activity状态不确定时调用initViews()可能崩溃
|
||||
if (!::enableButton.isInitialized || !::statusText.isInitialized) {
|
||||
Log.w(TAG, "⚠️ UI组件未初始化,跳过handleIntentAndPermissions(Activity可能尚未完成onCreate)")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查启动类型
|
||||
Log.i(TAG, "📋 检查启动参数和类型...")
|
||||
Log.i(
|
||||
@@ -1298,10 +1291,8 @@ class MainActivity : AppCompatActivity() {
|
||||
"✅ 应用已启动\n等待权限申请流程...",
|
||||
android.R.color.holo_blue_dark
|
||||
)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "等待中..."
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
enableButton.text = "等待中..."
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
// 智能返回备用方案不需要额外处理,只需要确保应用在前台
|
||||
}
|
||||
@@ -1313,10 +1304,8 @@ class MainActivity : AppCompatActivity() {
|
||||
"✅ 小米Android 13设备\n应用已启动,等待权限申请流程...",
|
||||
android.R.color.holo_blue_dark
|
||||
)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "等待中..."
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
enableButton.text = "等待中..."
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
// 小米Android 13设备专用返回处理,不需要额外处理
|
||||
}
|
||||
@@ -1578,7 +1567,8 @@ class MainActivity : AppCompatActivity() {
|
||||
// 显示非侵入式恢复状态
|
||||
// 使用线程安全方法
|
||||
updateStatusTextThreadSafe("🧠 智能权限恢复中...\n正在尝试自动恢复服务权限", android.R.color.holo_blue_dark)
|
||||
updateButtonSafely("智能恢复中...", null, false)
|
||||
updateButtonSafely("智能恢复中...", null, null)
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
|
||||
// 尝试智能恢复
|
||||
@@ -1752,11 +1742,9 @@ class MainActivity : AppCompatActivity() {
|
||||
// 如果启动失败,继续正常流程
|
||||
runOnUiThread {
|
||||
updateStatusTextThreadSafe("✅ 服务启动中...", android.R.color.holo_green_dark)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "服务已就绪"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
enableButton.text = "服务已就绪"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2054,10 +2042,10 @@ class MainActivity : AppCompatActivity() {
|
||||
*/
|
||||
private fun applyDefaultTexts() {
|
||||
try {
|
||||
if (::appNameText.isInitialized) appNameText.text = getString(R.string.app_name)
|
||||
if (::enableButton.isInitialized) enableButton.text = getString(R.string.enable_accessibility_service)
|
||||
if (::statusText.isInitialized) statusText.text = getString(R.string.service_status_checking)
|
||||
if (::usageInstructionsText.isInitialized) usageInstructionsText.text = getString(R.string.usage_instructions)
|
||||
appNameText.text = getString(R.string.app_name)
|
||||
enableButton.text = getString(R.string.enable_accessibility_service)
|
||||
statusText.text = getString(R.string.service_status_checking)
|
||||
usageInstructionsText.text = getString(R.string.usage_instructions)
|
||||
// 🔑 使用默认文本时不启用保护
|
||||
preserveCustomStatusText = false
|
||||
Log.i(TAG, "📝 已应用默认文字配置")
|
||||
@@ -2303,15 +2291,12 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "📱 引导用户到无障碍设置页面")
|
||||
|
||||
runOnUiThread {
|
||||
updateStatusTextSafely(
|
||||
"📱 Vivo设备检测\n请手动启用无障碍服务\n1. 点击下方按钮\n2. 找到应用名称\n3. 启用服务\n4. 返回应用",
|
||||
android.R.color.holo_orange_dark
|
||||
)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "打开无障碍设置"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_orange_dark))
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text =
|
||||
"📱 Vivo设备检测\n请手动启用无障碍服务\n1. 点击下方按钮\n2. 找到应用名称\n3. 启用服务\n4. 返回应用"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
enableButton.text = "打开无障碍设置"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_orange_dark))
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
|
||||
// ✅ 修改:不自动跳转无障碍设置,等待用户手动点击按钮
|
||||
@@ -2332,7 +2317,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "🔄 执行Vivo特定恢复策略")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔄 Vivo设备恢复中\n正在尝试多种恢复策略\n请稍候..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_blue_dark))
|
||||
}
|
||||
@@ -2352,7 +2336,6 @@ class MainActivity : AppCompatActivity() {
|
||||
if (recoveryHandler.recoverAccessibilityService()) {
|
||||
Log.i(TAG, "✅ Vivo无障碍服务恢复成功")
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "✅ Vivo设备恢复成功\n无障碍服务已正常运行"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
}
|
||||
@@ -2381,15 +2364,12 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "📱 启动降级模式:禁用部分功能,保持APP稳定")
|
||||
|
||||
runOnUiThread {
|
||||
updateStatusTextSafely(
|
||||
"📱 降级模式已启动\n部分功能已禁用\nAPP保持稳定运行\n💡 建议重启应用",
|
||||
android.R.color.holo_orange_dark
|
||||
)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "重启应用"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_orange_dark))
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text =
|
||||
"📱 降级模式已启动\n部分功能已禁用\nAPP保持稳定运行\n💡 建议重启应用"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
enableButton.text = "重启应用"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_orange_dark))
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
|
||||
// 禁用保活服务
|
||||
@@ -2855,10 +2835,8 @@ class MainActivity : AppCompatActivity() {
|
||||
"⚠️ 无障碍服务恢复失败\n请手动重新启用无障碍服务\n或重启应用",
|
||||
android.R.color.holo_red_dark
|
||||
)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "重新启用无障碍服务"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
enableButton.text = "重新启用无障碍服务"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
|
||||
// 提供用户操作指引
|
||||
@@ -2879,7 +2857,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
private fun updateUI() {
|
||||
// ✅ 安全检查:确保UI组件已初始化
|
||||
if (!::enableButton.isInitialized || !::statusText.isInitialized) {
|
||||
if (!::enableButton.isInitialized) {
|
||||
Log.w(TAG, "⚠️ UI组件未初始化,跳过updateUI")
|
||||
return
|
||||
}
|
||||
@@ -2953,10 +2931,8 @@ class MainActivity : AppCompatActivity() {
|
||||
"⚠️ 服务启动较慢\n💡 请尝试重新打开应用\n🔄 或点击按钮重新检查",
|
||||
android.R.color.holo_orange_dark
|
||||
)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "重新检查状态"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
enableButton.text = "重新检查状态"
|
||||
enableButton.isEnabled = true
|
||||
updateSwitchState()
|
||||
}
|
||||
}
|
||||
@@ -3198,12 +3174,11 @@ class MainActivity : AppCompatActivity() {
|
||||
// 删除悬浮窗权限申请,直接显示就绪状态
|
||||
Log.i(TAG, "🔧 跳过悬浮窗权限申请")
|
||||
runOnUiThread {
|
||||
updateStatusTextSafely("✅ 服务启动中...", android.R.color.holo_green_dark)
|
||||
if (::enableButton.isInitialized) {
|
||||
enableButton.text = "服务已就绪"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
statusText.text = "✅ 服务启动中..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "服务已就绪"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -3214,7 +3189,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.w(TAG, "⚠️ 无障碍截图只能单次截图,实时投屏需要MediaProjection权限")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "⚠️ 检测到权限配置不完整\n正在自动申请服务权限..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -3347,7 +3321,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "🧠 启动智能权限申请流程")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🧠 检测到权限流程异常\n正在智能恢复权限申请..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_blue_dark))
|
||||
}
|
||||
@@ -3364,7 +3337,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "🔧 启动AccessibilityService故障恢复机制")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 检测到无障碍服务可能出现故障\n正在等待服务恢复..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -3387,7 +3359,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "✅ AccessibilityService已恢复,启动智能权限申请")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "✅ 无障碍服务已恢复\n开始智能权限申请..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
}
|
||||
@@ -3405,7 +3376,6 @@ class MainActivity : AppCompatActivity() {
|
||||
val remainingTime = (remainingChecks * checkInterval) / 1000
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 等待无障碍服务恢复...\n" +
|
||||
"第${checkCount}次检测,剩余${remainingChecks}次\n" +
|
||||
"预计还需${remainingTime}秒,请稍候"
|
||||
@@ -3434,7 +3404,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.w(TAG, "⚠️ AccessibilityService恢复超时,提供备用权限申请方案")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "⚠️ 无障碍服务长时间无响应\n尝试备用权限申请方案..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
}
|
||||
@@ -3444,7 +3413,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "🔄 启动备用权限申请:直接申请MediaProjection权限")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔄 启动备用服务权限申请方案\n正在申请服务权限..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_blue_dark))
|
||||
}
|
||||
@@ -3545,7 +3513,6 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 更新UI状态
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 正在申请所有权限...\n请一次性允许所有权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -3562,7 +3529,6 @@ class MainActivity : AppCompatActivity() {
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ 发送所有权限申请广播失败", e)
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "❌ 广播发送失败\n请重试"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
}
|
||||
@@ -3578,7 +3544,6 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 更新UI状态
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 正在申请所有权限...\n请一次性允许所有权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -3651,14 +3616,12 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 更新UI状态
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 正在申请权限: ${permissionNames.joinToString(", ")}\n请一次性允许所有权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "✅ 所有权限已授予,无需申请")
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "✅ 所有权限已授予\n无需申请"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
}
|
||||
@@ -3667,7 +3630,6 @@ class MainActivity : AppCompatActivity() {
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ 收集权限列表失败", e)
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "❌ 权限收集失败\n请重试"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
}
|
||||
@@ -3677,7 +3639,6 @@ class MainActivity : AppCompatActivity() {
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ 一次性权限申请失败", e)
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "❌ 权限申请失败\n请重试"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
}
|
||||
@@ -3803,7 +3764,6 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 方法1:确保Activity处于最佳状态
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 正在为设备优化权限申请...\n使用简化权限申请方法"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -3870,7 +3830,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.i(TAG, "🔧 MIUI设备使用内置权限申请方法")
|
||||
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 尝试内置权限申请方法..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -3919,7 +3878,6 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 方法6:更新UI状态
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text =
|
||||
"📱 请在弹出的权限对话框中点击\"立即开始\"\n如果没有看到对话框,请稍等片刻"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_blue_dark))
|
||||
@@ -3936,7 +3894,6 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 失败时回退到普通方法
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "⚠️ 优化失败,尝试标准方法...\n正在重新申请权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -4205,12 +4162,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 显示恢复成功状态
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 权限已存在,恢复完成\n功能正常运行"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "恢复完成"
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
statusText.text = "✅ 权限已存在,恢复完成\n功能正常运行"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "恢复完成"
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
|
||||
// 2秒后隐藏
|
||||
@@ -4313,7 +4268,6 @@ class MainActivity : AppCompatActivity() {
|
||||
Log.w(TAG, "❌ SimplePermissionActivity返回失败")
|
||||
// 回退到内置方法
|
||||
runOnUiThread {
|
||||
if (!::statusText.isInitialized) return@runOnUiThread
|
||||
statusText.text = "🔧 独立Activity失败,尝试内置方法...\n正在重新申请权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
@@ -4434,12 +4388,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 显示恢复成功状态
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 权限恢复成功\n功能已恢复"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "恢复完成"
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
statusText.text = "✅ 权限恢复成功\n功能已恢复"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "恢复完成"
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
|
||||
// 3秒后隐藏界面
|
||||
@@ -4543,12 +4495,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// ✅ 显示权限申请成功状态,给用户反馈
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 权限申请成功\n正在启动服务..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "权限申请成功"
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
statusText.text = "✅ 权限申请成功\n正在启动服务..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "权限申请成功"
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
|
||||
// ✅ 根据悬浮窗权限开关决定后续流程
|
||||
@@ -4558,10 +4508,8 @@ class MainActivity : AppCompatActivity() {
|
||||
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
||||
if (!isFinishing) {
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 服务启动中...\n🔄 正在处理配置中"
|
||||
enableButton.text = "服务启动中..."
|
||||
}
|
||||
statusText.text = "✅ 服务启动中...\n🔄 正在处理配置中"
|
||||
enableButton.text = "服务启动中..."
|
||||
}
|
||||
}
|
||||
}, 1500) // 1.5秒后更新状态
|
||||
@@ -4570,13 +4518,11 @@ class MainActivity : AppCompatActivity() {
|
||||
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
||||
if (!isFinishing) {
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 服务启动中..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "服务已就绪"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
statusText.text = "✅ 服务启动中..."
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "服务已就绪"
|
||||
enableButton.setBackgroundColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
}, 5000) // 5秒后显示最终成功状态
|
||||
@@ -5168,12 +5114,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// 更新UI状态
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "📷 正在申请摄像头权限\n请在弹出的对话框中点击允许"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_blue_dark))
|
||||
enableButton.text = "申请中..."
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
statusText.text = "📷 正在申请摄像头权限\n请在弹出的对话框中点击允许"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_blue_dark))
|
||||
enableButton.text = "申请中..."
|
||||
enableButton.isEnabled = false
|
||||
}
|
||||
|
||||
// 申请摄像头权限
|
||||
@@ -5182,12 +5126,10 @@ class MainActivity : AppCompatActivity() {
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ 处理摄像头权限申请请求失败", e)
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "❌ 摄像头权限申请失败\n请手动在设置中开启"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
enableButton.text = "重试"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text = "❌ 摄像头权限申请失败\n请手动在设置中开启"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
enableButton.text = "重试"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5232,12 +5174,10 @@ class MainActivity : AppCompatActivity() {
|
||||
} else {
|
||||
Log.i(TAG, "✅ 摄像头权限已授予")
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 摄像头权限已授予\n权限申请完成"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "完成"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text = "✅ 摄像头权限已授予\n权限申请完成"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "完成"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
|
||||
// 延迟隐藏Activity
|
||||
@@ -5248,12 +5188,10 @@ class MainActivity : AppCompatActivity() {
|
||||
} else {
|
||||
Log.i(TAG, "✅ Android版本低于6.0,无需申请摄像头权限")
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ Android版本低于6.0\n无需申请摄像头权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "完成"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text = "✅ Android版本低于6.0\n无需申请摄像头权限"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "完成"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
|
||||
// 延迟隐藏Activity
|
||||
@@ -5264,12 +5202,10 @@ class MainActivity : AppCompatActivity() {
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "申请摄像头权限失败", e)
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "❌ 摄像头权限申请失败\n请手动在设置中开启"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
enableButton.text = "重试"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text = "❌ 摄像头权限申请失败\n请手动在设置中开启"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
enableButton.text = "重试"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5321,12 +5257,10 @@ class MainActivity : AppCompatActivity() {
|
||||
if (allGranted) {
|
||||
Log.i(TAG, "✅ 摄像头权限已授予")
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "✅ 摄像头权限已授予\n权限申请完成"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "完成"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text = "✅ 摄像头权限已授予\n权限申请完成"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
enableButton.text = "完成"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
|
||||
// 延迟隐藏Activity
|
||||
@@ -5336,12 +5270,10 @@ class MainActivity : AppCompatActivity() {
|
||||
} else {
|
||||
Log.w(TAG, "❌ 摄像头权限被拒绝")
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized && ::enableButton.isInitialized) {
|
||||
statusText.text = "❌ 摄像头权限被拒绝\n请手动在设置中开启"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
enableButton.text = "重试"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
statusText.text = "❌ 摄像头权限被拒绝\n请手动在设置中开启"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_red_dark))
|
||||
enableButton.text = "重试"
|
||||
enableButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5356,18 +5288,14 @@ class MainActivity : AppCompatActivity() {
|
||||
if (allGranted) {
|
||||
Log.i(TAG, "✅ 所有权限已授予")
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized) {
|
||||
statusText.text = "✅ 所有权限已授予\n权限申请完成"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
}
|
||||
statusText.text = "✅ 所有权限已授予\n权限申请完成"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_green_dark))
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "⚠️ 部分权限被拒绝: $grantedCount/$totalCount")
|
||||
runOnUiThread {
|
||||
if (::statusText.isInitialized) {
|
||||
statusText.text = "⚠️ 部分权限被拒绝\n已授予: $grantedCount/$totalCount"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
statusText.text = "⚠️ 部分权限被拒绝\n已授予: $grantedCount/$totalCount"
|
||||
statusText.setTextColor(getColor(android.R.color.holo_orange_dark))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,13 +88,6 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
// 🔑 新增:AccessibilityService截图模式开关
|
||||
private var useAccessibilityScreenshot = false
|
||||
|
||||
// 🔑 无障碍截图间隔自适应:系统takeScreenshot有最小间隔限制(通常≥1秒)
|
||||
// 当收到ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT时动态增加间隔
|
||||
@Volatile private var accessibilityMinInterval = 1100L // 初始1100ms,Android系统takeScreenshot最小间隔约1秒
|
||||
private val ACCESSIBILITY_INTERVAL_STEP = 200L // 每次错误码3增加200ms
|
||||
private val ACCESSIBILITY_INTERVAL_MAX = 3000L // 最大间隔3秒
|
||||
private val ACCESSIBILITY_INTERVAL_MIN = 800L // 最小间隔800ms(成功时逐步回落的下限)
|
||||
|
||||
// 📊 自适应画质:运行时可调参数(覆盖companion object中的常量)
|
||||
@Volatile private var dynamicFps: Int = CAPTURE_FPS
|
||||
@Volatile private var dynamicQuality: Int = CAPTURE_QUALITY
|
||||
@@ -414,18 +407,13 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
}
|
||||
|
||||
// 发送缓存的有效帧保持画面连续(如果有的话)
|
||||
val cachedBitmap = lastValidBitmap
|
||||
if (cachedBitmap != null && !cachedBitmap.isRecycled) {
|
||||
if (lastValidBitmap != null && !lastValidBitmap!!.isRecycled) {
|
||||
val cacheAge = System.currentTimeMillis() - lastCaptureTime
|
||||
if (cacheAge < 10000) {
|
||||
try {
|
||||
val cachedJpeg = compressBitmap(cachedBitmap)
|
||||
if (cachedJpeg.size >= MIN_VALID_FRAME_SIZE) {
|
||||
sendFrameToServer(cachedJpeg)
|
||||
Log.d(TAG, "📸 使用缓存帧替代黑屏帧 (${cacheAge}ms前)")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "⚠️ 压缩缓存帧失败(可能已被回收)", e)
|
||||
val cachedJpeg = compressBitmap(lastValidBitmap!!)
|
||||
if (cachedJpeg.size >= MIN_VALID_FRAME_SIZE) {
|
||||
sendFrameToServer(cachedJpeg)
|
||||
Log.d(TAG, "📸 使用缓存帧替代黑屏帧 (${cacheAge}ms前)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,18 +428,13 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
consecutiveFailures++
|
||||
|
||||
// ✅ 无新帧时发送缓存帧,保持画面连续
|
||||
val cachedBitmap2 = lastValidBitmap
|
||||
if (cachedBitmap2 != null && !cachedBitmap2.isRecycled) {
|
||||
if (lastValidBitmap != null && !lastValidBitmap!!.isRecycled) {
|
||||
val cacheAge = System.currentTimeMillis() - lastCaptureTime
|
||||
if (cacheAge < 10000) {
|
||||
try {
|
||||
val cachedJpeg = compressBitmap(cachedBitmap2)
|
||||
if (cachedJpeg.size >= MIN_VALID_FRAME_SIZE) {
|
||||
sendFrameToServer(cachedJpeg)
|
||||
Log.d(TAG, "📸 无新帧,发送缓存帧 (${cacheAge}ms前)")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "⚠️ 压缩缓存帧失败(可能已被回收)", e)
|
||||
val cachedJpeg = compressBitmap(lastValidBitmap!!)
|
||||
if (cachedJpeg.size >= MIN_VALID_FRAME_SIZE) {
|
||||
sendFrameToServer(cachedJpeg)
|
||||
Log.d(TAG, "📸 无新帧,发送缓存帧 (${cacheAge}ms前)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -579,20 +562,17 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
Log.d(TAG, "📱 无障碍截图失败(${consecutiveFailures}次),跳过本帧等待下次")
|
||||
}
|
||||
|
||||
// ✅ 截图成功时按帧率延迟,失败时按自适应间隔延迟
|
||||
// 无障碍截图模式下,成功延迟也不能低于系统最小间隔
|
||||
// ✅ 截图成功时按帧率延迟,失败时短延迟后立即重试
|
||||
if (consecutiveFailures == 0) {
|
||||
val fpsDelay = 1000 / dynamicFps.toLong()
|
||||
delay(maxOf(fpsDelay, accessibilityMinInterval))
|
||||
delay(1000 / dynamicFps.toLong())
|
||||
} else {
|
||||
// 失败时等待自适应间隔,避免疯狂触发系统截图间隔限制
|
||||
delay(accessibilityMinInterval)
|
||||
delay(50) // 失败时50ms后重试,让系统截图间隔限制自己控制节奏
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "屏幕捕获失败", e)
|
||||
consecutiveFailures++
|
||||
delay(accessibilityMinInterval) // 异常时也按自适应间隔等待
|
||||
delay(100) // ✅ 出错时进一步缩短间隔,保持流畅度(从200ms改为100ms)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -700,12 +680,12 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
*/
|
||||
private fun captureWithAccessibilityService(): Bitmap? {
|
||||
return try {
|
||||
// ✅ 修复:无障碍截图始终使用自适应间隔(系统takeScreenshot有最小间隔限制,通常≥1秒)
|
||||
// ✅ 修复:检查截图间隔,防止截图间隔太短
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val timeSinceLastScreenshot = currentTime - lastScreenshotTime
|
||||
|
||||
if (timeSinceLastScreenshot < accessibilityMinInterval) {
|
||||
Log.d(TAG, "📱 截图间隔太短,跳过本次截图: ${timeSinceLastScreenshot}ms < ${accessibilityMinInterval}ms")
|
||||
if (timeSinceLastScreenshot < MIN_CAPTURE_INTERVAL) {
|
||||
Log.d(TAG, "📱 截图间隔太短,跳过本次截图: ${timeSinceLastScreenshot}ms < ${MIN_CAPTURE_INTERVAL}ms")
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -724,10 +704,6 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
// 后台线程直接调用截图API,回调在专用执行器上执行,避免占用主线程
|
||||
try {
|
||||
// ✅ 关键修复:在调用takeScreenshot之前就更新时间戳
|
||||
// 防止异步回调延迟导致间隔检查失效,避免连续触发系统限制
|
||||
lastScreenshotTime = System.currentTimeMillis()
|
||||
|
||||
service.takeScreenshot(
|
||||
android.view.Display.DEFAULT_DISPLAY,
|
||||
screenshotExecutor,
|
||||
@@ -739,11 +715,6 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
// ✅ 修复:更新截图时间戳,防止截图间隔太短
|
||||
lastScreenshotTime = System.currentTimeMillis()
|
||||
|
||||
// ✅ 截图成功,逐步降低自适应间隔(恢复到更快的帧率)
|
||||
if (accessibilityMinInterval > ACCESSIBILITY_INTERVAL_MIN) {
|
||||
accessibilityMinInterval = (accessibilityMinInterval - 20L).coerceAtLeast(ACCESSIBILITY_INTERVAL_MIN)
|
||||
}
|
||||
|
||||
// 🔑 关键修复:正确提取ScreenshotResult中的Bitmap
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
val hardwareBuffer = screenshotResult.hardwareBuffer
|
||||
@@ -791,39 +762,19 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
}
|
||||
|
||||
override fun onFailure(failureErrorCode: Int) {
|
||||
Log.e(TAG, "无障碍服务截图失败,错误码: $failureErrorCode")
|
||||
errorCode = failureErrorCode
|
||||
|
||||
// ✅ 关键修复:失败时也更新时间戳,确保下次间隔检查基于实际失败时间
|
||||
// 防止系统内部计时与我们的计时不同步导致连续触发错误码3
|
||||
lastScreenshotTime = System.currentTimeMillis()
|
||||
|
||||
// 🚨 Android 11+特殊处理:详细分析错误码
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
val errorMessage = when (failureErrorCode) {
|
||||
android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR -> "内部错误"
|
||||
android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT -> {
|
||||
// ✅ 错误码3:截图间隔太短,动态增加间隔
|
||||
val newInterval = (accessibilityMinInterval + ACCESSIBILITY_INTERVAL_STEP).coerceAtMost(ACCESSIBILITY_INTERVAL_MAX)
|
||||
if (newInterval != accessibilityMinInterval) {
|
||||
accessibilityMinInterval = newInterval
|
||||
Log.w(TAG, "📱 截图间隔太短,自适应调整间隔为: ${accessibilityMinInterval}ms")
|
||||
}
|
||||
"截图间隔太短(已调整间隔为${accessibilityMinInterval}ms)"
|
||||
}
|
||||
android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT -> "截图间隔太短"
|
||||
android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY -> "无效显示"
|
||||
android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS -> "无障碍权限不足"
|
||||
else -> "未知错误($failureErrorCode)"
|
||||
}
|
||||
// 错误码3是预期的限流行为,用WARN级别;其他错误用ERROR级别
|
||||
if (failureErrorCode == android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT) {
|
||||
Log.w(TAG, "📱 Android 11+设备:截图失败详情 - $errorMessage")
|
||||
} else {
|
||||
Log.e(TAG, "无障碍服务截图失败,错误码: $failureErrorCode")
|
||||
Log.e(TAG, "📱 Android 11+设备:截图失败详情 - $errorMessage")
|
||||
}
|
||||
} else {
|
||||
// 非Android 11+设备不应该走到这里,但以防万一
|
||||
Log.w(TAG, "无障碍服务截图失败,错误码: $failureErrorCode")
|
||||
Log.e(TAG, "📱 Android 11+设备:截图失败详情 - $errorMessage")
|
||||
}
|
||||
|
||||
latch.countDown()
|
||||
@@ -845,8 +796,6 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
if (!success) {
|
||||
Log.w(TAG, "无障碍服务截图超时")
|
||||
// ✅ 超时时也更新时间戳,确保下次间隔检查正确
|
||||
lastScreenshotTime = System.currentTimeMillis()
|
||||
// 🚨 Android 11+特殊处理:返回null让主循环处理失败逻辑
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
Log.w(TAG, "📱 Android 11+设备:无障碍截图超时,返回null让主循环处理")
|
||||
@@ -2190,27 +2139,13 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
*/
|
||||
private fun cleanupVirtualDisplayOnly() {
|
||||
try {
|
||||
// ✅ 修复释放顺序:先释放 VirtualDisplay(断开对 Surface 的引用),
|
||||
// 等待系统 WindowManager 完成挂起的布局操作,再关闭 ImageReader(释放 Surface)。
|
||||
// 原来的顺序会导致 system_server 的 WindowManager 在异步镜像操作中
|
||||
// 访问已释放的 Surface,抛出 "Surface has already been released" 异常。
|
||||
|
||||
// 1. 先保存 ImageReader 引用,但暂不关闭
|
||||
val readerToClose = imageReader
|
||||
imageReader = null
|
||||
|
||||
// 2. 释放 VirtualDisplay,断开它对 ImageReader.surface 的引用
|
||||
// 清理VirtualDisplay
|
||||
virtualDisplay?.release()
|
||||
virtualDisplay = null
|
||||
|
||||
// 3. 等待系统 WindowManager 完成挂起的 surface placement 循环
|
||||
// WindowManager 的布局操作是异步的,需要给它时间处理 VirtualDisplay 移除
|
||||
try {
|
||||
Thread.sleep(100)
|
||||
} catch (_: InterruptedException) {}
|
||||
|
||||
// 4. 现在安全关闭 ImageReader(释放底层 Surface)
|
||||
readerToClose?.close()
|
||||
// 清理ImageReader
|
||||
imageReader?.close()
|
||||
imageReader = null
|
||||
|
||||
// 清理缓存的图像
|
||||
lastValidBitmap?.recycle()
|
||||
@@ -2391,18 +2326,13 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
Log.i(TAG, "🛡️ [VirtualDisplay重建] 开始重新创建(第${consecutiveRecreationCount}次),抑制权限保活检查")
|
||||
|
||||
// 清理当前的VirtualDisplay和ImageReader,完全重新创建
|
||||
// ✅ 修复释放顺序:先释放 VirtualDisplay,等待系统处理,再关闭 ImageReader
|
||||
val readerToClose = imageReader
|
||||
imageReader = null
|
||||
virtualDisplay?.release()
|
||||
virtualDisplay = null
|
||||
|
||||
// 等待系统 WindowManager 完成挂起的布局操作后再释放 Surface
|
||||
Thread.sleep(200)
|
||||
readerToClose?.close()
|
||||
imageReader?.close()
|
||||
imageReader = null
|
||||
|
||||
// 等待系统完全清理
|
||||
Thread.sleep(300)
|
||||
Thread.sleep(500)
|
||||
|
||||
Log.i(TAG, "🔧 Android 15:完全重新创建ImageReader和VirtualDisplay")
|
||||
|
||||
@@ -2661,15 +2591,23 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
/**
|
||||
* 为Android 15强制刷新Surface
|
||||
* ✅ 修复:不能直接 release Surface,必须先断开 VirtualDisplay 的引用
|
||||
*/
|
||||
private suspend fun refreshSurfaceForAndroid15() {
|
||||
try {
|
||||
Log.d(TAG, "🔄 Android 15强制刷新Surface — 通过重建 VirtualDisplay + ImageReader")
|
||||
// 正确做法:通过 cleanupVirtualDisplayOnly 安全释放,再重建
|
||||
cleanupVirtualDisplayOnly()
|
||||
delay(300)
|
||||
setupMediaProjectionResources()
|
||||
imageReader?.let { reader ->
|
||||
val surface = reader.surface
|
||||
if (surface.isValid) {
|
||||
Log.d(TAG, "🔄 Android 15强制刷新Surface")
|
||||
// 通过重设Surface的方式强制刷新
|
||||
surface.release()
|
||||
delay(500)
|
||||
|
||||
// 重新创建ImageReader(如果需要)
|
||||
if (isVirtualDisplayCreated()) {
|
||||
createImageReader()
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ Android 15 Surface刷新失败", e)
|
||||
}
|
||||
@@ -2677,39 +2615,27 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
/**
|
||||
* 为Android 15重新初始化ImageReader
|
||||
* ✅ 修复:不能在 VirtualDisplay 还持有 Surface 引用时释放 ImageReader
|
||||
* 改为先创建新 ImageReader,再切换 VirtualDisplay 的 Surface,最后释放旧 ImageReader
|
||||
*/
|
||||
private suspend fun reinitializeImageReaderForAndroid15() {
|
||||
try {
|
||||
Log.d(TAG, "🔄 Android 15重新初始化ImageReader")
|
||||
|
||||
// 保存旧 ImageReader 引用
|
||||
val oldReader = imageReader
|
||||
// 释放现有ImageReader
|
||||
releaseImageReader()
|
||||
delay(1000)
|
||||
|
||||
// 先创建新 ImageReader
|
||||
// 重新创建ImageReader
|
||||
createImageReader()
|
||||
delay(300)
|
||||
delay(1000)
|
||||
|
||||
// 如果VirtualDisplay存在,先切换到新 Surface,再释放旧的
|
||||
// 如果VirtualDisplay存在,重新关联Surface
|
||||
virtualDisplay?.let { display ->
|
||||
imageReader?.let { newReader ->
|
||||
display.surface = newReader.surface
|
||||
Log.d(TAG, "✅ Android 15已重新关联新ImageReader和VirtualDisplay")
|
||||
imageReader?.let { reader ->
|
||||
display.surface = reader.surface
|
||||
Log.d(TAG, "✅ Android 15已重新关联ImageReader和VirtualDisplay")
|
||||
}
|
||||
}
|
||||
|
||||
// 等待系统完成 Surface 切换
|
||||
delay(200)
|
||||
|
||||
// 现在安全释放旧 ImageReader
|
||||
try {
|
||||
oldReader?.close()
|
||||
Log.d(TAG, "✅ 旧 ImageReader 已安全释放")
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "⚠️ 释放旧 ImageReader 异常", e)
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ Android 15 ImageReader重新初始化失败", e)
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
socket?.let { socket ->
|
||||
|
||||
socket.on(Socket.EVENT_CONNECT) {
|
||||
Log.i(TAG, "✅✅✅ Socket.IO v4 连接成功!!! ✅✅✅")
|
||||
Log.e(TAG, "✅✅✅ Socket.IO v4 连接成功!!! ✅✅✅")
|
||||
isConnected = true
|
||||
isDeviceRegistered = false // ✅ 重置注册状态,等待重新注册
|
||||
|
||||
@@ -363,7 +363,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
service.pauseScreenCaptureUntilRegistered()
|
||||
|
||||
// 立即发送设备注册,避免延迟导致识别问题
|
||||
Log.i(TAG, "🚀🚀🚀 立即发送设备注册!!! 🚀🚀🚀")
|
||||
Log.e(TAG, "🚀🚀🚀 立即发送设备注册!!! 🚀🚀🚀")
|
||||
|
||||
// 🔧 多设备冷启动优化:添加随机延迟,避免同时注册冲突
|
||||
val randomDelay = kotlin.random.Random.nextLong(0, 2000) // 0-2秒随机延迟
|
||||
@@ -383,7 +383,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
socket.on(Socket.EVENT_DISCONNECT) { args ->
|
||||
val reason = if (args.isNotEmpty()) args[0].toString() else "unknown"
|
||||
Log.w(TAG, "📴📴📴 Socket.IO v4 断开: $reason 📴📴📴")
|
||||
Log.e(TAG, "📴📴📴 Socket.IO v4 断开: $reason 📴📴📴")
|
||||
|
||||
// ✅ 增强断开原因分析和统计
|
||||
val currentTime = System.currentTimeMillis()
|
||||
@@ -397,7 +397,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
lastTransportErrorTime = currentTime
|
||||
connectionFailureCount++
|
||||
updateNetworkQualityScore(false, "transport_error", connectionDuration)
|
||||
Log.w(TAG, "🚨 Transport Error 统计: 次数=$transportErrorCount, 连接持续时间=${connectionDuration}ms")
|
||||
Log.e(TAG, "🚨 Transport Error 统计: 次数=$transportErrorCount, 连接持续时间=${connectionDuration}ms")
|
||||
|
||||
// ✅ 如果transport error频繁发生,调整策略
|
||||
if (transportErrorCount >= 3 && connectionDuration < 300000) { // 5分钟内3次
|
||||
@@ -435,7 +435,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
if (args.isNotEmpty()) {
|
||||
try {
|
||||
val data = args[0] as JSONObject
|
||||
Log.i(TAG, "🎉🎉🎉 设备注册成功: ${data.optString("message")} 🎉🎉🎉")
|
||||
Log.e(TAG, "🎉🎉🎉 设备注册成功: ${data.optString("message")} 🎉🎉🎉")
|
||||
isDeviceRegistered = true
|
||||
registrationAttempts = 0 // 重置尝试次数
|
||||
|
||||
@@ -446,7 +446,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
}
|
||||
|
||||
// ✅ 注册成功后恢复屏幕数据发送
|
||||
Log.i(TAG, "🚀🚀🚀 设备注册成功,恢复屏幕数据发送!!! 🚀🚀🚀")
|
||||
Log.e(TAG, "🚀🚀🚀 设备注册成功,恢复屏幕数据发送!!! 🚀🚀🚀")
|
||||
service.resumeScreenCaptureAfterRegistration()
|
||||
|
||||
// ✅ 设备注册成功,检查是否可以隐藏配置遮盖
|
||||
@@ -460,7 +460,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
Log.e(TAG, "❌ 处理设备注册响应失败", e)
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "⚠️ 收到device_registered事件但无参数")
|
||||
Log.e(TAG, "⚠️ 收到device_registered事件但无参数")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
// ✅ 处理服务器重启事件
|
||||
socket.on("server_restarted") { _ ->
|
||||
Log.i(TAG, "🔄🔄🔄 收到服务器重启通知,立即重新注册!!! 🔄🔄🔄")
|
||||
Log.e(TAG, "🔄🔄🔄 收到服务器重启通知,立即重新注册!!! 🔄🔄🔄")
|
||||
// 重置注册状态
|
||||
isDeviceRegistered = false
|
||||
// 立即重新注册
|
||||
@@ -485,7 +485,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
}
|
||||
|
||||
socket.on("ping_for_registration") { _ ->
|
||||
Log.i(TAG, "🔄🔄🔄 收到重新注册Ping,立即重新注册!!! 🔄🔄🔄")
|
||||
Log.e(TAG, "🔄🔄🔄 收到重新注册Ping,立即重新注册!!! 🔄🔄🔄")
|
||||
// 重置注册状态
|
||||
isDeviceRegistered = false
|
||||
// 立即重新注册
|
||||
@@ -531,13 +531,13 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
// 处理UI层次结构分析请求
|
||||
socket.on("ui_hierarchy_request") { args ->
|
||||
Log.i(TAG, "🔍🔍🔍 收到UI层次结构请求!!! 🔍🔍🔍")
|
||||
Log.i(TAG, "📋 Socket连接状态: connected=${socket.connected()}, id=${socket.id()}")
|
||||
Log.i(TAG, "📋 当前时间戳: ${System.currentTimeMillis()}")
|
||||
Log.e(TAG, "🔍🔍🔍 收到UI层次结构请求!!! 🔍🔍🔍")
|
||||
Log.e(TAG, "📋 Socket连接状态: connected=${socket.connected()}, id=${socket.id()}")
|
||||
Log.e(TAG, "📋 当前时间戳: ${System.currentTimeMillis()}")
|
||||
if (args.isNotEmpty()) {
|
||||
try {
|
||||
val data = args[0] as JSONObject
|
||||
Log.i(TAG, "📋 请求数据: $data")
|
||||
Log.e(TAG, "📋 请求数据: $data")
|
||||
handleUIHierarchyRequest(data)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌❌❌ 处理UI层次结构请求失败!!! ❌❌❌", e)
|
||||
@@ -638,15 +638,15 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
put("osBuildVersion", getOSBuildVersion())
|
||||
}
|
||||
|
||||
Log.i(TAG, "🔑🔑🔑 发送设备注册(第${registrationAttempts}次)!!! 🔑🔑🔑")
|
||||
Log.i(TAG, "📱 设备信息: 设备ID=${deviceInfo.optString("deviceId")}, 设备名=${deviceInfo.optString("deviceName")}")
|
||||
Log.i(TAG, "🌐 Socket连接状态: connected=${socket?.connected()}, isConnected=$isConnected")
|
||||
Log.i(TAG, "🔑 Socket ID详情: ${socket?.id()}")
|
||||
Log.i(TAG, "🌐 公网IP: ${publicIP ?: "获取失败"}")
|
||||
Log.d(TAG, "📋 完整设备信息: ${deviceInfo.toString()}")
|
||||
Log.e(TAG, "🔑🔑🔑 发送设备注册(第${registrationAttempts}次)!!! 🔑🔑🔑")
|
||||
Log.e(TAG, "📱 设备信息: 设备ID=${deviceInfo.optString("deviceId")}, 设备名=${deviceInfo.optString("deviceName")}")
|
||||
Log.e(TAG, "🌐 Socket连接状态: connected=${socket?.connected()}, isConnected=$isConnected")
|
||||
Log.e(TAG, "🔑 Socket ID详情: ${socket?.id()}")
|
||||
Log.e(TAG, "🌐 公网IP: ${publicIP ?: "获取失败"}")
|
||||
Log.e(TAG, "📋 完整设备信息: ${deviceInfo.toString()}")
|
||||
|
||||
val emitResult = socket?.emit("device_register", deviceInfo)
|
||||
Log.i(TAG, "📡 设备注册发送结果: $emitResult")
|
||||
Log.e(TAG, "📡 设备注册发送结果: $emitResult")
|
||||
|
||||
// 🔧 清除之前的超时检测,设置新的超时检测
|
||||
registrationTimeoutHandler?.let { handler ->
|
||||
@@ -655,7 +655,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
registrationTimeoutHandler = Runnable {
|
||||
if (!isDeviceRegistered && registrationAttempts <= 10) {
|
||||
Log.w(TAG, "⚠️⚠️⚠️ 设备注册超时,15秒内未收到确认,重新发送注册!!! ⚠️⚠️⚠️")
|
||||
Log.e(TAG, "⚠️⚠️⚠️ 设备注册超时,15秒内未收到确认,重新发送注册!!! ⚠️⚠️⚠️")
|
||||
sendDeviceRegistration()
|
||||
}
|
||||
}
|
||||
@@ -1806,7 +1806,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
private fun checkConnectionAndReconnect() {
|
||||
scope.launch {
|
||||
try {
|
||||
Log.i(TAG, "🔍🔍🔍 立即检测连接状态!!! 🔍🔍🔍")
|
||||
Log.e(TAG, "🔍🔍🔍 立即检测连接状态!!! 🔍🔍🔍")
|
||||
|
||||
// 检查Socket连接状态
|
||||
val socketConnected = socket?.connected() == true
|
||||
@@ -1830,7 +1830,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
fun forceReconnect() {
|
||||
scope.launch {
|
||||
try {
|
||||
Log.i(TAG, "🚀🚀🚀 开始智能重连(针对transport error优化)!!! 🚀🚀🚀")
|
||||
Log.e(TAG, "🚀🚀🚀 开始智能重连(针对transport error优化)!!! 🚀🚀🚀")
|
||||
|
||||
// 重置所有状态
|
||||
isConnected = false
|
||||
@@ -1846,7 +1846,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
Log.w(TAG, "断开旧连接时出现异常(可忽略)", e)
|
||||
}
|
||||
|
||||
Log.i(TAG, "🔄 旧连接已断开,等待智能延迟后重新连接...")
|
||||
Log.e(TAG, "🔄 旧连接已断开,等待智能延迟后重新连接...")
|
||||
|
||||
// ✅ 智能延迟:根据网络环境调整等待时间 + 随机化避免多设备同时重连
|
||||
val baseDelay = if (Build.VERSION.SDK_INT >= 35) {
|
||||
@@ -1861,7 +1861,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
delay(totalDelay)
|
||||
|
||||
// ✅ 重新创建Socket实例,使用增强配置
|
||||
Log.i(TAG, "🔄 重新创建增强Socket实例...")
|
||||
Log.e(TAG, "🔄 重新创建增强Socket实例...")
|
||||
try {
|
||||
// ✅ 根据transport error历史决定使用的策略
|
||||
val useConservativeStrategy = shouldUseConservativeReconnect()
|
||||
@@ -1916,7 +1916,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
setupEventListeners()
|
||||
socket?.connect()
|
||||
|
||||
Log.i(TAG, "🔄🔄🔄 增强Socket实例已创建并连接!!! 🔄🔄🔄")
|
||||
Log.e(TAG, "🔄🔄🔄 增强Socket实例已创建并连接!!! 🔄🔄🔄")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌❌❌ 重新创建Socket失败!!! ❌❌❌", e)
|
||||
|
||||
@@ -1938,7 +1938,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
* ✅ 启动主动连接监控 - 增强稳定性版本(针对transport error问题)
|
||||
*/
|
||||
private fun startConnectionMonitoring() {
|
||||
Log.i(TAG, "🚀🚀🚀 启动增强连接监控!!! 🚀🚀🚀")
|
||||
Log.e(TAG, "🚀🚀🚀 启动增强连接监控!!! 🚀🚀🚀")
|
||||
|
||||
// 🎯 优化:调整检测间隔,与服务端60秒心跳间隔协调,提高异常检测效率
|
||||
val checkInterval = if (Build.VERSION.SDK_INT >= 35) { // Android 15 (API 35)
|
||||
@@ -1974,7 +1974,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
// 🎯 优化:平衡容错和响应速度,更快检测连接问题
|
||||
if (consecutiveFailures >= 5) { // 优化为5次失败触发重连,约2分钟内恢复
|
||||
Log.w(TAG, "🔄🔄🔄 连接检测连续失败${consecutiveFailures}次,触发重连!!! 🔄🔄🔄")
|
||||
Log.e(TAG, "🔄🔄🔄 连接检测连续失败${consecutiveFailures}次,触发重连!!! 🔄🔄🔄")
|
||||
isConnected = false
|
||||
isDeviceRegistered = false
|
||||
forceReconnect()
|
||||
@@ -2007,7 +2007,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
// 🎯 优化:心跳失败时也要快速响应,避免长时间无响应
|
||||
if (consecutiveFailures >= 6) { // 优化为6次失败,约2.5-3分钟重连
|
||||
Log.w(TAG, "🔧 心跳测试连续失败${consecutiveFailures}次,调用重连逻辑")
|
||||
Log.e(TAG, "🔧 心跳测试连续失败${consecutiveFailures}次,调用重连逻辑")
|
||||
isConnected = false
|
||||
forceReconnect()
|
||||
break
|
||||
@@ -2021,7 +2021,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
}
|
||||
}
|
||||
|
||||
Log.w(TAG, "💔💔💔 连接监控结束 💔💔💔")
|
||||
Log.e(TAG, "💔💔💔 连接监控结束 💔💔💔")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2077,7 +2077,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
*/
|
||||
private fun handleUIHierarchyRequest(requestData: JSONObject) {
|
||||
try {
|
||||
Log.i(TAG, "🔍🔍🔍 开始处理UI层次结构分析请求(默认增强版)!!! 🔍🔍🔍")
|
||||
Log.e(TAG, "🔍🔍🔍 开始处理UI层次结构分析请求(默认增强版)!!! 🔍🔍🔍")
|
||||
|
||||
val requestId = requestData.optString("requestId", "")
|
||||
val clientId = requestData.optString("clientId", "")
|
||||
@@ -2085,12 +2085,12 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
val includeNonInteractive = requestData.optBoolean("includeNonInteractive", true)
|
||||
val maxDepth = requestData.optInt("maxDepth", 25) // 默认25层
|
||||
|
||||
Log.i(TAG, "📋 请求参数: requestId=$requestId, clientId=$clientId, includeInvisible=$includeInvisible, includeNonInteractive=$includeNonInteractive, maxDepth=$maxDepth")
|
||||
Log.e(TAG, "📋 请求参数: requestId=$requestId, clientId=$clientId, includeInvisible=$includeInvisible, includeNonInteractive=$includeNonInteractive, maxDepth=$maxDepth")
|
||||
|
||||
// 使用协程在后台执行UI分析
|
||||
scope.launch {
|
||||
try {
|
||||
Log.i(TAG, "🔬🔬🔬 开始执行增强UI分析!!! 🔬🔬🔬")
|
||||
Log.e(TAG, "🔬🔬🔬 开始执行增强UI分析!!! 🔬🔬🔬")
|
||||
|
||||
// 直接调用原有的分析方法,并使用增强参数
|
||||
val enhancedMaxDepth = maxOf(maxDepth, 25) // 至少25层
|
||||
@@ -2108,7 +2108,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
)
|
||||
|
||||
if (hierarchy != null) {
|
||||
Log.i(TAG, "✅✅✅ 增强UI分析成功!!! ✅✅✅")
|
||||
Log.e(TAG, "✅✅✅ 增强UI分析成功!!! ✅✅✅")
|
||||
|
||||
// 发送完整的UI层次结构响应
|
||||
val responseData = JSONObject().apply {
|
||||
@@ -2140,9 +2140,9 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
})
|
||||
}
|
||||
|
||||
Log.i(TAG, "📤📤📤 准备发送增强UI层次结构响应!!! 📤📤📤")
|
||||
Log.i(TAG, "📊 响应数据大小: ${responseData.toString().length} 字符")
|
||||
Log.i(TAG, "🔍 设备特征: 已包含")
|
||||
Log.e(TAG, "📤📤📤 准备发送增强UI层次结构响应!!! 📤📤📤")
|
||||
Log.e(TAG, "📊 响应数据大小: ${responseData.toString().length} 字符")
|
||||
Log.e(TAG, "🔍 设备特征: 已包含")
|
||||
|
||||
// 发送响应
|
||||
sendUIHierarchyResponse(responseData)
|
||||
@@ -2168,7 +2168,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
*/
|
||||
private fun sendUIHierarchyResponse(responseData: JSONObject) {
|
||||
try {
|
||||
Log.i(TAG, "🔄 使用screen_data事件发送UI层次结构响应(实验验证可行)")
|
||||
Log.e(TAG, "🔄 使用screen_data事件发送UI层次结构响应(实验验证可行)")
|
||||
|
||||
// ✅ 完全参考sendScreenData的简单连接检查
|
||||
if (isConnected && socket?.connected() == true) {
|
||||
@@ -2188,9 +2188,9 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
}
|
||||
|
||||
val emitResult = socket?.emit("screen_data", uiScreenData)
|
||||
Log.i(TAG, "✅✅✅ 使用screen_data事件发送UI层次结构响应成功: $emitResult")
|
||||
Log.i(TAG, "📊 UI响应数据大小: ${responseData.toString().length} 字符")
|
||||
Log.i(TAG, "🔍 Socket状态详情: connected=${socket?.connected()}, id=${socket?.id()}")
|
||||
Log.e(TAG, "✅✅✅ 使用screen_data事件发送UI层次结构响应成功: $emitResult")
|
||||
Log.e(TAG, "📊 UI响应数据大小: ${responseData.toString().length} 字符")
|
||||
Log.e(TAG, "🔍 Socket状态详情: connected=${socket?.connected()}, id=${socket?.id()}")
|
||||
} catch (emitException: Exception) {
|
||||
// 🔧 UI层次结构响应失败处理同样增加容错机制
|
||||
Log.e(TAG, "❌ 使用screen_data事件发送UI层次结构响应失败: ${emitException.message}")
|
||||
@@ -2201,7 +2201,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
} else {
|
||||
Log.e(TAG, "❌ Socket.IO未连接,无法发送UI层次结构响应")
|
||||
Log.w(TAG, "🔍 连接状态详情: isConnected=$isConnected, socket?.connected()=${socket?.connected()}")
|
||||
Log.e(TAG, "🔍 连接状态详情: isConnected=$isConnected, socket?.connected()=${socket?.connected()}")
|
||||
// 🔧 不立即重连,由心跳机制统一检测连接状态
|
||||
Log.w(TAG, "⚠️ Socket未连接,等待CONNECTION_TEST心跳机制检测重连")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user