ScreenController.kt 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package com.example.modifier.service
  2. import android.accessibilityservice.AccessibilityService
  3. import android.accessibilityservice.GestureDescription
  4. import android.content.Intent
  5. import android.graphics.Path
  6. import android.graphics.Rect
  7. import android.provider.Settings
  8. import android.util.Log
  9. import android.view.accessibility.AccessibilityNodeInfo
  10. import com.draco.ladb.utils.ADB
  11. import com.example.modifier.TraverseResult
  12. import com.example.modifier.constants.CMD_BACK
  13. import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY
  14. import com.example.modifier.utils.currentActivity
  15. import com.example.modifier.utils.findAllScrollable
  16. import com.example.modifier.utils.findFirstByDesc
  17. import com.example.modifier.utils.findFirstByIdAndText
  18. import com.example.modifier.utils.findFirstScrollable
  19. import com.example.modifier.utils.shellRun
  20. import kotlinx.coroutines.delay
  21. import kotlinx.coroutines.withTimeoutOrNull
  22. class ScreenController(val context: AccessibilityService, private val inspector: ScreenInspector) {
  23. companion object {
  24. private const val TAG = "ScreenController"
  25. }
  26. suspend fun toggleRcsSwitch(state: Boolean, retry: Int = 3): Boolean {
  27. val res = TraverseResult()
  28. shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 2")
  29. val success = run repeatBlock@{
  30. repeat(retry) {
  31. res.rcsSwitch = null
  32. inspector.traverseNode(res)
  33. if (res.rcsSwitch == null) {
  34. shellRun(CMD_BACK, "sleep 0.5", CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
  35. } else {
  36. if (res.rcsSwitch!!.isChecked == state) {
  37. return@repeatBlock true
  38. }
  39. val rect = Rect()
  40. res.rcsSwitch!!.getBoundsInScreen(rect)
  41. if (state) {
  42. shellRun(
  43. "input tap ${rect.centerX()} ${rect.centerY()}", "sleep 1",
  44. )
  45. val btn =
  46. context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
  47. .firstOrNull()
  48. if (btn != null) {
  49. btn.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  50. delay(1000)
  51. }
  52. while (currentActivity()?.contains("RcsSettingsActivity") == true ||
  53. currentActivity()?.contains("TurnOffRcsActivity") == true
  54. ) {
  55. shellRun(CMD_BACK)
  56. delay(500)
  57. }
  58. shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
  59. } else {
  60. shellRun(
  61. "input tap ${rect.centerX()} ${rect.centerY()}", "sleep 1",
  62. )
  63. if (currentActivity()?.contains("TurnOffRcsActivity") == true) {
  64. inspector.traverseNode(res)
  65. if (res.closeBtn != null) {
  66. val rect1 = Rect()
  67. res.closeBtn!!.getBoundsInScreen(rect1)
  68. shellRun(
  69. "input tap ${rect1.centerX()} ${rect1.centerY()}", "sleep 1",
  70. )
  71. }
  72. } else {
  73. context.rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
  74. .firstOrNull()?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  75. }
  76. delay(1000)
  77. while (currentActivity()?.contains("RcsSettingsActivity") == true ||
  78. currentActivity()?.contains("TurnOffRcsActivity") == true
  79. ) {
  80. shellRun(CMD_BACK)
  81. delay(500)
  82. }
  83. shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
  84. }
  85. res.rcsSwitch = null
  86. inspector.traverseNode(res)
  87. if (res.rcsSwitch?.isChecked == state) {
  88. return@repeatBlock true
  89. }
  90. }
  91. }
  92. false
  93. }
  94. while (currentActivity()?.contains("RcsSettingsActivity") == true) {
  95. shellRun(CMD_BACK)
  96. delay(500)
  97. }
  98. return success
  99. }
  100. suspend fun adbPair(): Pair<String, String>? {
  101. val i = Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)
  102. i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
  103. i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
  104. context.startActivity(i)
  105. delay(500)
  106. withTimeoutOrNull(10000) {
  107. while (true) {
  108. val node = context.rootInActiveWindow.findFirstByIdAndText(
  109. "android:id/title",
  110. "Wireless debugging"
  111. )
  112. if (node != null) {
  113. Log.i(TAG, "found wireless debugging")
  114. delay(500)
  115. tapNode(node)
  116. delay(1000)
  117. return@withTimeoutOrNull context.rootInActiveWindow.findFirstByIdAndText(
  118. "android:id/title",
  119. "Pair device with pairing code"
  120. )?.let {
  121. Log.i(TAG, "found pair device with pairing code")
  122. it.parent.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  123. delay(1000)
  124. val code = context.rootInActiveWindow.findAccessibilityNodeInfosByViewId(
  125. "com.android.settings:id/pairing_code"
  126. ).firstOrNull()?.text?.toString()
  127. val ip = context.rootInActiveWindow.findAccessibilityNodeInfosByViewId(
  128. "com.android.settings:id/ip_addr"
  129. ).firstOrNull()?.text?.toString()
  130. Log.i(TAG, "pairing code: $code, ip: $ip")
  131. if (code != null && ip != null) {
  132. return@let Pair(code, ip)
  133. } else {
  134. }
  135. }
  136. return@withTimeoutOrNull
  137. }
  138. context.rootInActiveWindow.findAllScrollable().forEach {
  139. Log.i(TAG, "scrolling ${it.viewIdResourceName}")
  140. it.performAction(AccessibilityNodeInfo.ACTION_FOCUS)
  141. it.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
  142. }
  143. delay(500)
  144. }
  145. null
  146. }
  147. }
  148. fun tapNode(node: AccessibilityNodeInfo) {
  149. val rect = Rect()
  150. node.getBoundsInScreen(rect)
  151. val path = Path()
  152. path.moveTo(rect.centerX().toFloat(), rect.centerY().toFloat())
  153. context.dispatchGesture(
  154. GestureDescription.Builder().addStroke(
  155. GestureDescription.StrokeDescription(path, 0, 100)
  156. ).build(), null, null
  157. )
  158. }
  159. }