ModifierService.kt 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. package com.example.modifier.service
  2. import android.accessibilityservice.AccessibilityService
  3. import android.annotation.SuppressLint
  4. import android.content.Context
  5. import android.graphics.PixelFormat
  6. import android.os.Build
  7. import android.util.DisplayMetrics
  8. import android.util.Log
  9. import android.view.Gravity
  10. import android.view.LayoutInflater
  11. import android.view.MotionEvent
  12. import android.view.View
  13. import android.view.View.GONE
  14. import android.view.View.OnTouchListener
  15. import android.view.View.VISIBLE
  16. import android.view.WindowManager
  17. import android.view.accessibility.AccessibilityEvent
  18. import android.widget.CompoundButton
  19. import android.widget.FrameLayout
  20. import androidx.annotation.MenuRes
  21. import androidx.appcompat.widget.PopupMenu
  22. import androidx.core.content.ContextCompat
  23. import com.example.modifier.BuildConfig
  24. import com.example.modifier.R
  25. import com.example.modifier.baseTag
  26. import com.example.modifier.TraverseResult
  27. import com.example.modifier.data.AppDatabase
  28. import com.example.modifier.data.AppPreferences
  29. import com.example.modifier.data.AppState
  30. import com.example.modifier.databinding.FloatingWindowBinding
  31. import com.example.modifier.enums.RequestNumberState
  32. import com.example.modifier.model.SpoofedSimInfo
  33. import com.example.modifier.repo.AppPreferencesRepository
  34. import com.example.modifier.repo.AppStateRepository
  35. import com.example.modifier.repo.BackupRepository
  36. import com.example.modifier.repo.GoogleMessageStateRepository
  37. import com.example.modifier.repo.SpoofedSimInfoRepository
  38. import com.example.modifier.utils.clearConv
  39. import com.example.modifier.utils.hasRootAccess
  40. import com.example.modifier.utils.isRebooted
  41. import com.example.modifier.utils.killPhoneProcess
  42. import com.example.modifier.utils.optimize
  43. import com.example.modifier.utils.restartSelf
  44. import com.example.modifier.utils.setBatteryLevel
  45. import com.example.modifier.utils.syncTime
  46. import com.google.android.material.color.DynamicColors
  47. import kotlinx.coroutines.CoroutineScope
  48. import kotlinx.coroutines.Dispatchers
  49. import kotlinx.coroutines.delay
  50. import kotlinx.coroutines.flow.StateFlow
  51. import kotlinx.coroutines.launch
  52. import kotlinx.coroutines.withContext
  53. import java.util.Timer
  54. import java.util.TimerTask
  55. import java.util.concurrent.atomic.AtomicReference
  56. import kotlin.math.max
  57. import kotlin.math.min
  58. import kotlin.time.Duration.Companion.minutes
  59. import kotlin.time.Duration.Companion.seconds
  60. @SuppressLint("SetTextI18n")
  61. class ModifierService : AccessibilityService() {
  62. private val tag = "$baseTag/AccessibilityService"
  63. companion object {
  64. const val NAME: String = BuildConfig.APPLICATION_ID + ".service.ModifierService"
  65. @JvmStatic
  66. var instance: ModifierService? = null
  67. private set
  68. }
  69. private lateinit var binding: FloatingWindowBinding
  70. private val backupItemDao by lazy { AppDatabase.getDatabase(this).itemDao() }
  71. private val appPreferencesRepository by lazy { AppPreferencesRepository(this) }
  72. private lateinit var appPreferences: StateFlow<AppPreferences>
  73. private val appStateRepository: AppStateRepository by lazy { AppStateRepository(this) }
  74. private lateinit var appState: StateFlow<AppState>
  75. private val googleMessageStateRepository by lazy { GoogleMessageStateRepository(this) }
  76. private val screenInspector by lazy { ScreenInspector(this) }
  77. private val screenController by lazy { ScreenController(this, screenInspector) }
  78. private val spoofedSimInfoRepository by lazy { SpoofedSimInfoRepository(this) }
  79. private lateinit var spoofedSimInfo: StateFlow<SpoofedSimInfo>
  80. private val backupRepository by lazy {
  81. BackupRepository(
  82. this,
  83. backupItemDao,
  84. spoofedSimInfoRepository
  85. )
  86. }
  87. private lateinit var socketClient: SocketClient
  88. private lateinit var taskRunner: TaskRunner
  89. override fun onAccessibilityEvent(event: AccessibilityEvent) {}
  90. override fun onInterrupt() {
  91. Log.e(tag, "onInterrupt")
  92. }
  93. @SuppressLint("ClickableViewAccessibility")
  94. override fun onServiceConnected() {
  95. super.onServiceConnected()
  96. Log.i(tag, "onServiceConnected")
  97. instance = this
  98. val displayMetrics = DisplayMetrics()
  99. val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
  100. windowManager.defaultDisplay.getMetrics(displayMetrics)
  101. val height = displayMetrics.heightPixels
  102. val width = displayMetrics.widthPixels
  103. val mLayout = FrameLayout(this)
  104. val layoutParams = WindowManager.LayoutParams()
  105. layoutParams.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
  106. layoutParams.format = PixelFormat.TRANSLUCENT
  107. layoutParams.flags = layoutParams.flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
  108. layoutParams.flags = layoutParams.flags or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
  109. layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT
  110. layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
  111. layoutParams.x = 0
  112. layoutParams.y = 800
  113. layoutParams.gravity = Gravity.START or Gravity.TOP
  114. val newContext = DynamicColors.wrapContextIfAvailable(applicationContext, R.style.AppTheme)
  115. val inflater = LayoutInflater.from(newContext)
  116. binding = FloatingWindowBinding.inflate(inflater, mLayout, true)
  117. binding.tvVersion.text = "v${BuildConfig.VERSION_CODE}"
  118. windowManager.addView(mLayout, layoutParams)
  119. var maxX = 0
  120. var maxY = 0
  121. binding.root.measure(View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY)
  122. binding.root.post {
  123. maxX = width - binding.root.measuredWidth
  124. maxY = height - binding.root.measuredHeight
  125. Log.i(tag, "measured: $maxX, $maxY")
  126. layoutParams.x = maxX
  127. windowManager.updateViewLayout(mLayout, layoutParams)
  128. }
  129. val downX = AtomicReference(0f)
  130. val downY = AtomicReference(0f)
  131. val downParamX = AtomicReference(0)
  132. val downParamY = AtomicReference(0)
  133. val touchListener = OnTouchListener { v, event ->
  134. when (event.action) {
  135. MotionEvent.ACTION_DOWN -> {
  136. downX.set(event.rawX)
  137. downY.set(event.rawY)
  138. downParamX.set(layoutParams.x)
  139. downParamY.set(layoutParams.y)
  140. }
  141. MotionEvent.ACTION_MOVE -> {
  142. layoutParams.x = min(
  143. max((downParamX.get() + (event.rawX - downX.get())).toDouble(), 0.0),
  144. maxX.toDouble()
  145. )
  146. .toInt()
  147. layoutParams.y = min(
  148. max((downParamY.get() + (event.rawY - downY.get())).toDouble(), 0.0),
  149. maxY.toDouble()
  150. )
  151. .toInt()
  152. windowManager.updateViewLayout(mLayout, layoutParams)
  153. }
  154. MotionEvent.ACTION_UP -> {
  155. return@OnTouchListener event.eventTime - event.downTime >= 200
  156. }
  157. }
  158. false
  159. }
  160. CoroutineScope(Dispatchers.IO).launch {
  161. appPreferences = appPreferencesRepository.stateFlow()
  162. appState = appStateRepository.stateFlow()
  163. spoofedSimInfo = spoofedSimInfoRepository.stateFlow()
  164. taskRunner = TaskRunner(
  165. this@ModifierService,
  166. screenInspector,
  167. screenController,
  168. appStateRepository,
  169. appPreferencesRepository,
  170. spoofedSimInfoRepository,
  171. googleMessageStateRepository,
  172. backupRepository,
  173. )
  174. launch {
  175. appState.collect {
  176. withContext(Dispatchers.Main) {
  177. binding.swSend.isChecked = it.send
  178. binding.btnReq.isEnabled = !it.requesting
  179. binding.tvCount.text = "${it.successNum} / ${it.executedNum}"
  180. if (it.suspended) {
  181. binding.btnReq.backgroundTintList = ContextCompat.getColorStateList(
  182. binding.root.context,
  183. R.color.btn_color_error
  184. )
  185. } else {
  186. binding.btnReq.backgroundTintList = ContextCompat.getColorStateList(
  187. binding.root.context,
  188. R.color.btn_color
  189. )
  190. }
  191. when (it.requestNumberState) {
  192. RequestNumberState.IDLE -> {
  193. binding.tvStatus.visibility = GONE
  194. binding.tvStatus.text = ""
  195. }
  196. RequestNumberState.RESET -> {
  197. binding.tvStatus.visibility = VISIBLE
  198. binding.tvStatus.text = "Reset GMS"
  199. }
  200. RequestNumberState.BACKUP -> {
  201. binding.tvStatus.visibility = VISIBLE
  202. binding.tvStatus.text = "backing up"
  203. }
  204. RequestNumberState.REQUEST -> {
  205. binding.tvStatus.visibility = VISIBLE
  206. binding.tvStatus.text = "requesting number"
  207. }
  208. RequestNumberState.OTP_1 -> {
  209. binding.tvStatus.visibility = VISIBLE
  210. binding.tvStatus.text = "waiting for OTP sent"
  211. }
  212. RequestNumberState.OTP_2 -> {
  213. binding.tvStatus.visibility = VISIBLE
  214. binding.tvStatus.text = "waiting for OTP received"
  215. }
  216. RequestNumberState.CONFIG -> {
  217. binding.tvStatus.visibility = VISIBLE
  218. binding.tvStatus.text = "waiting for configuration"
  219. }
  220. }
  221. }
  222. withContext(Dispatchers.IO) {
  223. reportDeviceStatues()
  224. }
  225. }
  226. }
  227. launch {
  228. appPreferences.collect {
  229. withContext(Dispatchers.Main) {
  230. binding.swSend.text = it.name
  231. }
  232. if (this@ModifierService::socketClient.isInitialized) {
  233. socketClient.disconnect()
  234. }
  235. socketClient = SocketClient(
  236. appPreferences.value.id,
  237. appPreferences.value.server,
  238. appPreferences.value.name,
  239. taskRunner
  240. )
  241. }
  242. }
  243. launch {
  244. spoofedSimInfo.collect {
  245. withContext(Dispatchers.Main) {
  246. binding.tvCountry.text = it.country
  247. }
  248. }
  249. }
  250. appStateRepository.updateRuntimeFlags(preparing = true)
  251. val hasRoot = run checkRoot@{
  252. repeat(30) {
  253. if (hasRootAccess()) {
  254. return@checkRoot true
  255. }
  256. delay(1000)
  257. }
  258. false
  259. }
  260. if (!hasRoot) {
  261. System.exit(0)
  262. }
  263. CoroutineScope(kotlin.coroutines.coroutineContext).launch {
  264. googleMessageStateRepository.startLogging()
  265. }
  266. if (isRebooted()) {
  267. delay(2.minutes)
  268. } else {
  269. delay(5000)
  270. }
  271. optimize()
  272. syncTime()
  273. if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
  274. killPhoneProcess(force = false)
  275. }
  276. appStateRepository.updateRuntimeFlags(preparing = false)
  277. val timer = Timer()
  278. timer.schedule(object : TimerTask() {
  279. override fun run() {
  280. reportDeviceStatues()
  281. }
  282. }, 0, 3.seconds.inWholeMilliseconds)
  283. if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
  284. timer.schedule(object : TimerTask() {
  285. override fun run() {
  286. CoroutineScope(Dispatchers.IO).launch {
  287. try {
  288. setBatteryLevel(100)
  289. } catch (e: Exception) {
  290. e.printStackTrace()
  291. }
  292. }
  293. }
  294. }, 0, 30.minutes.inWholeMilliseconds)
  295. }
  296. }
  297. binding.swSend.setOnTouchListener(touchListener)
  298. binding.swSend.setOnCheckedChangeListener { buttonView: CompoundButton?, isChecked: Boolean ->
  299. CoroutineScope(Dispatchers.IO).launch {
  300. appStateRepository.updateSend(isChecked)
  301. }
  302. }
  303. googleMessageStateRepository.logs.observeForever {
  304. binding.tvLog.text = it
  305. binding.scroll.fullScroll(View.FOCUS_DOWN)
  306. }
  307. binding.btnReq.setOnClickListener {
  308. CoroutineScope(Dispatchers.IO).launch {
  309. taskRunner.requestNumber(reset = false, noBackup = true)
  310. }
  311. }
  312. binding.btnReset.setOnClickListener {
  313. binding.btnReset.isEnabled = false
  314. CoroutineScope(Dispatchers.IO).launch {
  315. taskRunner.reset()
  316. withContext(Dispatchers.Main) {
  317. binding.btnReset.isEnabled = true
  318. }
  319. }
  320. }
  321. binding.btnMore.setOnClickListener {
  322. showMenu(newContext, binding.btnMore, R.menu.more)
  323. }
  324. }
  325. private fun showMenu(context: Context, v: View, @MenuRes menuRes: Int) {
  326. val popup = PopupMenu(context, v)
  327. popup.menuInflater.inflate(menuRes, popup.menu)
  328. popup.setOnMenuItemClickListener { item ->
  329. binding.btnMore.isEnabled = false
  330. CoroutineScope(Dispatchers.IO).launch {
  331. when (item.itemId) {
  332. R.id.inspect -> {
  333. delay(1500)
  334. screenInspector.traverseNode(TraverseResult())
  335. }
  336. R.id.check_availability -> {
  337. taskRunner.checkRcsA10y()
  338. }
  339. R.id.toggle_on -> {
  340. screenController.toggleRcsSwitch(true)
  341. }
  342. R.id.toggle_off -> {
  343. screenController.toggleRcsSwitch(false)
  344. }
  345. R.id.clear_conv -> {
  346. clearConv()
  347. appStateRepository.resetExecutedNum()
  348. }
  349. R.id.store_numbers -> {
  350. storeNumbers()
  351. }
  352. R.id.change_profile -> {
  353. }
  354. R.id.restart_modifier -> {
  355. restartSelf()
  356. }
  357. R.id.reset_counter -> {
  358. CoroutineScope(Dispatchers.IO).launch {
  359. appStateRepository.resetExecutedNum()
  360. appStateRepository.resetSuccessNum()
  361. appStateRepository.resetRequestedNum()
  362. }
  363. }
  364. }
  365. withContext(Dispatchers.Main) {
  366. binding.btnMore.isEnabled = true
  367. }
  368. }
  369. true
  370. }
  371. popup.setOnDismissListener {
  372. // Respond to popup being dismissed.
  373. }
  374. // Show the popup menu.
  375. popup.show()
  376. }
  377. private fun reportDeviceStatues() {
  378. if (this::socketClient.isInitialized) {
  379. socketClient.reportDeviceStatues(
  380. appState.value.send,
  381. appState.value.busy,
  382. spoofedSimInfo.value.country
  383. )
  384. }
  385. }
  386. private suspend fun storeNumbers() {
  387. // repeat(100) {
  388. // requestNumber(reset = true, fresh = it > 0)
  389. // delay(5000)
  390. // }
  391. }
  392. }