Helpers.kt 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package com.example.modifier
  2. import android.accessibilityservice.AccessibilityServiceInfo
  3. import android.content.Context
  4. import android.content.pm.PackageManager
  5. import android.text.TextUtils
  6. import android.util.Log
  7. import android.view.accessibility.AccessibilityManager
  8. import androidx.core.app.ActivityCompat
  9. import com.example.modifier.http.ktorClient
  10. import com.example.modifier.service.ModifierService
  11. import io.ktor.client.request.head
  12. import kotlinx.coroutines.Dispatchers
  13. import kotlinx.coroutines.coroutineScope
  14. import kotlinx.coroutines.launch
  15. import kotlinx.coroutines.withContext
  16. import java.time.ZoneId
  17. import java.time.ZonedDateTime
  18. import java.time.format.DateTimeFormatter
  19. import java.util.Locale
  20. private const val TAG = "Modifier"
  21. suspend fun shellRun(vararg commands: String): Pair<String, String> {
  22. var output = ""
  23. var error = ""
  24. Log.i(TAG, "shellRun: \t${commands.joinToString("\n\t\t\t")}")
  25. withContext(Dispatchers.IO) {
  26. val p = ProcessBuilder("su", "-M").start()
  27. p.outputStream.bufferedWriter().use { writer ->
  28. commands.forEach { command ->
  29. writer.write(command)
  30. writer.newLine()
  31. writer.flush()
  32. }
  33. }
  34. coroutineScope {
  35. launch {
  36. p.inputStream.bufferedReader().useLines {
  37. it.forEach {
  38. output += it + "\n"
  39. Log.i(TAG, "shellRunOut: $it")
  40. }
  41. }
  42. }
  43. launch {
  44. p.errorStream.bufferedReader().useLines {
  45. it.forEach {
  46. error += it + "\n"
  47. Log.e(TAG, "shellRunErr: $it")
  48. }
  49. }
  50. }
  51. }
  52. p.waitFor()
  53. }
  54. return Pair(output, error)
  55. }
  56. fun getContext(): Context? {
  57. try {
  58. val activityThreadClass = Class.forName("android.app.ActivityThread")
  59. val currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread")
  60. currentActivityThreadMethod.isAccessible = true
  61. val currentActivityThread = currentActivityThreadMethod.invoke(null)
  62. val getApplicationMethod = activityThreadClass.getMethod("getApplication")
  63. getApplicationMethod.isAccessible = true
  64. return getApplicationMethod.invoke(currentActivityThread) as Context
  65. } catch (e: java.lang.Exception) {
  66. e.printStackTrace()
  67. }
  68. return null
  69. }
  70. suspend fun hasRootAccess(): Boolean {
  71. var rootAccess = false
  72. try {
  73. val (output, _) = shellRun("echo \"imrooted\"")
  74. if (output.contains("imrooted")) {
  75. rootAccess = true
  76. }
  77. } catch (e: Exception) {
  78. e.printStackTrace()
  79. }
  80. return rootAccess
  81. }
  82. fun hasPermission(permission: String): Boolean {
  83. return ActivityCompat.checkSelfPermission(
  84. getContext()!!,
  85. permission
  86. ) == PackageManager.PERMISSION_GRANTED
  87. }
  88. fun isAccessibilityEnabled(): Boolean {
  89. val context = getContext()!!
  90. val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
  91. val enabledServices =
  92. am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
  93. for (enabledService in enabledServices) {
  94. Log.i(
  95. TAG,
  96. "Enabled service: " + enabledService.resolveInfo.serviceInfo.packageName + "/" + enabledService.resolveInfo.serviceInfo.name
  97. )
  98. val enabledServiceInfo = enabledService.resolveInfo.serviceInfo
  99. if (enabledServiceInfo.packageName == context.packageName && enabledServiceInfo.name == ModifierService.NAME) return true
  100. }
  101. return false
  102. }
  103. suspend fun enableAccessibility(): Boolean {
  104. if (isAccessibilityEnabled()) return true
  105. val context = getContext()!!
  106. val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
  107. val enabledServices =
  108. am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
  109. val names: MutableList<String?> = ArrayList()
  110. for (enabledService in enabledServices) {
  111. names.add(enabledService.resolveInfo.serviceInfo.packageName + "/" + enabledService.resolveInfo.serviceInfo.name)
  112. }
  113. names.add(context.packageName + "/" + ModifierService.NAME)
  114. try {
  115. shellRun(
  116. "settings put secure enabled_accessibility_services " + TextUtils.join(":", names),
  117. "settings put secure accessibility_enabled 1"
  118. )
  119. return true
  120. } catch (e: java.lang.Exception) {
  121. e.printStackTrace()
  122. }
  123. return false
  124. }
  125. suspend fun enableOverlay() {
  126. try {
  127. shellRun("appops set " + BuildConfig.APPLICATION_ID + " SYSTEM_ALERT_WINDOW allow")
  128. } catch (e: java.lang.Exception) {
  129. e.printStackTrace()
  130. }
  131. }
  132. suspend fun syncTime() {
  133. try {
  134. Log.i("Modifier", "syncTime: start")
  135. val response = ktorClient("").head("http://www.baidu.com")
  136. val dateHeader = response.headers["Date"]
  137. val date = ZonedDateTime.parse(
  138. dateHeader,
  139. DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH)
  140. )
  141. // convert to Asia/Shanghai
  142. val dateInZone = date.withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
  143. Log.i(
  144. TAG,
  145. "CurrentTime from Baidu: ${dateInZone.format(DateTimeFormatter.ISO_DATE_TIME)}"
  146. )
  147. shellRun(
  148. "settings put system time_12_24 24",
  149. "settings put global auto_time 0",
  150. "settings put global auto_time_zone 0",
  151. "setprop persist.sys.timezone Asia/Shanghai",
  152. "date \"${dateInZone.format(DateTimeFormatter.ofPattern("MMddHHmmyyyy.ss"))}\""
  153. )
  154. } catch (e: Exception) {
  155. Log.e(TAG, "Error SyncTime", e)
  156. }
  157. }