ModifierService.kt 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309
  1. package com.example.modifier.service
  2. import android.accessibilityservice.AccessibilityService
  3. import android.annotation.SuppressLint
  4. import android.content.ComponentName
  5. import android.content.Context
  6. import android.graphics.PixelFormat
  7. import android.os.Build
  8. import android.os.Handler
  9. import android.os.Looper
  10. import android.text.TextUtils
  11. import android.util.Base64
  12. import android.util.DisplayMetrics
  13. import android.util.Log
  14. import android.view.Gravity
  15. import android.view.LayoutInflater
  16. import android.view.MotionEvent
  17. import android.view.View
  18. import android.view.View.OnTouchListener
  19. import android.view.WindowManager
  20. import android.view.accessibility.AccessibilityEvent
  21. import android.view.accessibility.AccessibilityNodeInfo
  22. import android.widget.CompoundButton
  23. import android.widget.FrameLayout
  24. import androidx.annotation.MenuRes
  25. import androidx.appcompat.widget.PopupMenu
  26. import androidx.core.content.ContextCompat
  27. import com.example.modifier.BuildConfig
  28. import com.example.modifier.R
  29. import com.example.modifier.TraverseResult
  30. import com.example.modifier.constants.CMD_BACK
  31. import com.example.modifier.constants.CMD_CONVERSATION_LIST_ACTIVITY
  32. import com.example.modifier.constants.CMD_MESSAGING_APP
  33. import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY
  34. import com.example.modifier.constants.PACKAGE_GMS
  35. import com.example.modifier.constants.PACKAGE_MESSAGING
  36. import com.example.modifier.data.AppDatabase
  37. import com.example.modifier.data.AppPreferences
  38. import com.example.modifier.repo.AppPreferencesRepository
  39. import com.example.modifier.data.AppState
  40. import com.example.modifier.repo.AppStateRepository
  41. import com.example.modifier.repo.GoogleMessageStateRepository
  42. import com.example.modifier.databinding.FloatingWindowBinding
  43. import com.example.modifier.enums.RcsConfigureState
  44. import com.example.modifier.enums.RcsConnectionStatus
  45. import com.example.modifier.extension.kill
  46. import com.example.modifier.http.api.DeviceApi
  47. import com.example.modifier.http.api.RcsNumberApi
  48. import com.example.modifier.http.api.SysConfigApi
  49. import com.example.modifier.http.ktorClient
  50. import com.example.modifier.http.request.RcsNumberRequest
  51. import com.example.modifier.http.response.DeviceResponse
  52. import com.example.modifier.http.response.RcsNumberResponse
  53. import com.example.modifier.http.response.SysConfigResponse
  54. import com.example.modifier.model.InstallApkAction
  55. import com.example.modifier.model.SpoofedSimInfo
  56. import com.example.modifier.model.SocketCallback
  57. import com.example.modifier.model.TaskAction
  58. import com.example.modifier.model.TaskConfig
  59. import com.example.modifier.model.TaskExecutionResult
  60. import com.example.modifier.repo.BackupRepository
  61. import com.example.modifier.repo.SpoofedSimInfoRepository
  62. import com.example.modifier.serializer.Json
  63. import com.example.modifier.utils.changeClashProfile
  64. import com.example.modifier.utils.clearConv
  65. import com.example.modifier.utils.genICCID
  66. import com.example.modifier.utils.genIMEI
  67. import com.example.modifier.utils.genIMSI
  68. import com.example.modifier.utils.hasRootAccess
  69. import com.example.modifier.utils.isClashInstalled
  70. import com.example.modifier.utils.isOldVersion
  71. import com.example.modifier.utils.isRebooted
  72. import com.example.modifier.utils.killPhoneProcess
  73. import com.example.modifier.utils.optimize
  74. import com.example.modifier.utils.resetAll
  75. import com.example.modifier.utils.restartSelf
  76. import com.example.modifier.utils.setBatteryLevel
  77. import com.example.modifier.utils.shellRun
  78. import com.example.modifier.utils.smsIntent
  79. import com.example.modifier.utils.spoofSmsIntent
  80. import com.example.modifier.utils.stopClash
  81. import com.example.modifier.utils.syncTime
  82. import com.example.modifier.utils.uniqueId
  83. import com.google.android.material.color.DynamicColors
  84. import io.ktor.client.HttpClient
  85. import io.ktor.client.call.body
  86. import io.ktor.client.engine.okhttp.OkHttp
  87. import io.ktor.client.plugins.HttpResponseValidator
  88. import io.ktor.client.plugins.ServerResponseException
  89. import io.ktor.client.plugins.resources.get
  90. import io.ktor.client.plugins.resources.post
  91. import io.ktor.client.plugins.resources.put
  92. import io.ktor.client.plugins.timeout
  93. import io.ktor.client.request.prepareGet
  94. import io.ktor.client.request.setBody
  95. import io.ktor.http.ContentType
  96. import io.ktor.http.contentType
  97. import io.ktor.utils.io.ByteReadChannel
  98. import io.ktor.utils.io.core.isEmpty
  99. import io.ktor.utils.io.core.readBytes
  100. import io.socket.client.IO
  101. import io.socket.client.Socket
  102. import io.socket.emitter.Emitter
  103. import kotlinx.coroutines.CoroutineScope
  104. import kotlinx.coroutines.Dispatchers
  105. import kotlinx.coroutines.delay
  106. import kotlinx.coroutines.flow.StateFlow
  107. import kotlinx.coroutines.launch
  108. import kotlinx.coroutines.withContext
  109. import kotlinx.coroutines.withTimeout
  110. import kotlinx.coroutines.withTimeoutOrNull
  111. import kotlinx.serialization.encodeToString
  112. import org.json.JSONException
  113. import org.json.JSONObject
  114. import java.io.File
  115. import java.time.LocalDateTime
  116. import java.time.temporal.ChronoUnit
  117. import java.util.Timer
  118. import java.util.TimerTask
  119. import java.util.concurrent.atomic.AtomicReference
  120. import kotlin.math.max
  121. import kotlin.math.min
  122. import kotlin.time.Duration.Companion.hours
  123. import kotlin.time.Duration.Companion.minutes
  124. import kotlin.time.Duration.Companion.seconds
  125. @SuppressLint("SetTextI18n")
  126. class ModifierService : AccessibilityService(), Emitter.Listener {
  127. companion object {
  128. const val NAME: String = BuildConfig.APPLICATION_ID + ".service.ModifierService"
  129. @JvmStatic
  130. var instance: ModifierService? = null
  131. private set
  132. }
  133. private val handler = Handler(Looper.getMainLooper())
  134. private val mSocketOpts = IO.Options()
  135. private lateinit var mSocket: Socket
  136. private lateinit var binding: FloatingWindowBinding
  137. private var currentTaskId = 0
  138. private var lastSend = 0L
  139. private val backupItemDao by lazy {
  140. AppDatabase.getDatabase(this).itemDao()
  141. }
  142. private val appPreferencesRepository by lazy {
  143. AppPreferencesRepository(this)
  144. }
  145. private lateinit var appPreferences: StateFlow<AppPreferences>
  146. private val appStateRepository: AppStateRepository by lazy {
  147. AppStateRepository(this)
  148. }
  149. private lateinit var appState: StateFlow<AppState>
  150. private val googleMessageStateRepository by lazy {
  151. GoogleMessageStateRepository(this)
  152. }
  153. private var requestMode = 1;
  154. private var currentActivity = ""
  155. private val screenInspector by lazy {
  156. ScreenInspector(this)
  157. }
  158. private val screenController by lazy {
  159. ScreenController(this, screenInspector)
  160. }
  161. private val spoofedSimInfoRepository by lazy {
  162. SpoofedSimInfoRepository(this)
  163. }
  164. private lateinit var spoofedSimInfo: StateFlow<SpoofedSimInfo>
  165. private val backupRepository by lazy {
  166. BackupRepository(this, backupItemDao, spoofedSimInfoRepository)
  167. }
  168. fun connect() {
  169. try {
  170. if (this@ModifierService::mSocket.isInitialized) {
  171. mSocket.disconnect()
  172. }
  173. mSocketOpts.query =
  174. "model=${Build.MODEL}&name=${appPreferences.value.name}&id=${uniqueId}&version=${BuildConfig.VERSION_CODE}"
  175. mSocketOpts.transports = arrayOf("websocket")
  176. Log.i(com.example.modifier.TAG, "Connection query: ${mSocketOpts.query}")
  177. mSocket = IO.socket(appPreferences.value.server, mSocketOpts)
  178. mSocket.on("message", this@ModifierService)
  179. mSocket.on(Socket.EVENT_CONNECT) {
  180. Log.i(com.example.modifier.TAG, "Connected to server")
  181. CoroutineScope(Dispatchers.IO).launch {
  182. delay(500)
  183. reportDeviceStatues()
  184. }
  185. }
  186. mSocket.on(Socket.EVENT_DISCONNECT) {
  187. Log.i(com.example.modifier.TAG, "Disconnected from server")
  188. }
  189. mSocket.on(Socket.EVENT_CONNECT_ERROR) { args ->
  190. Log.i(com.example.modifier.TAG, "Connection error: " + args[0])
  191. if (args[0] is Exception) {
  192. val e = args[0] as Exception
  193. e.printStackTrace()
  194. }
  195. }
  196. mSocket.connect()
  197. } catch (e: Exception) {
  198. e.printStackTrace()
  199. }
  200. }
  201. override fun onCreate() {
  202. super.onCreate()
  203. Log.i(com.example.modifier.TAG, "Starting ModifierService")
  204. CoroutineScope(Dispatchers.IO).launch {
  205. appState = appStateRepository.getAppState()
  206. appPreferences = appPreferencesRepository.getAppPreferences()
  207. spoofedSimInfo = spoofedSimInfoRepository.stateFlow()
  208. appStateRepository.updateRuntimeFlags(preparing = true)
  209. val hasRoot = run checkRoot@{
  210. repeat(30) {
  211. if (hasRootAccess()) {
  212. return@checkRoot true
  213. }
  214. delay(1000)
  215. }
  216. false
  217. }
  218. if (!hasRoot) {
  219. System.exit(0)
  220. }
  221. launch {
  222. googleMessageStateRepository.startLogging()
  223. }
  224. if (isRebooted()) {
  225. delay(2.minutes)
  226. } else {
  227. delay(5000)
  228. }
  229. optimize()
  230. syncTime()
  231. if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
  232. killPhoneProcess(force = false)
  233. }
  234. appStateRepository.updateRuntimeFlags(preparing = false)
  235. connect()
  236. val timer = Timer()
  237. timer.schedule(object : TimerTask() {
  238. override fun run() {
  239. reportDeviceStatues()
  240. }
  241. }, 0, 3.seconds.inWholeMilliseconds)
  242. if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
  243. timer.schedule(object : TimerTask() {
  244. override fun run() {
  245. CoroutineScope(Dispatchers.IO).launch {
  246. try {
  247. setBatteryLevel(100)
  248. } catch (e: Exception) {
  249. e.printStackTrace()
  250. }
  251. }
  252. }
  253. }, 0, 30.minutes.inWholeMilliseconds)
  254. }
  255. }
  256. }
  257. override fun onAccessibilityEvent(event: AccessibilityEvent) {
  258. Log.d(
  259. com.example.modifier.TAG,
  260. "eventType: ${event.eventType}, packageName: ${event.packageName}, className: ${event.className}"
  261. )
  262. if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
  263. if (event.packageName != null && event.className != null) {
  264. val componentName = ComponentName(
  265. event.packageName.toString(),
  266. event.className.toString()
  267. )
  268. try {
  269. packageManager.getActivityInfo(componentName, 0)
  270. currentActivity = componentName.flattenToShortString()
  271. Log.d(com.example.modifier.TAG, "Activity: $currentActivity")
  272. } catch (_: Exception) {
  273. }
  274. }
  275. }
  276. }
  277. override fun onInterrupt() {
  278. }
  279. override fun call(vararg args: Any) {
  280. if (args.isNotEmpty()) {
  281. Log.i(com.example.modifier.TAG, "Received message: " + args[0])
  282. if (args[0] is JSONObject) {
  283. val json = args[0] as JSONObject
  284. val action = json.optString("action")
  285. if ("send" == action) {
  286. val data = json.optJSONObject("data")
  287. if (data != null) {
  288. val to = data.optString("to")
  289. val body = data.optString("body")
  290. CoroutineScope(Dispatchers.IO).launch {
  291. send(
  292. to, body, TaskConfig(
  293. rcsWait = 3000,
  294. rcsInterval = 1000,
  295. cleanCount = 10,
  296. requestNumberInterval = 50,
  297. checkConnection = true,
  298. useBackup = false,
  299. endToEndEncryption = true
  300. )
  301. )
  302. }
  303. }
  304. } else if ("task" == action) {
  305. val taskAction = Json.decodeFromString<TaskAction>(json.toString())
  306. CoroutineScope(Dispatchers.IO).launch {
  307. runTask(taskAction)
  308. }
  309. } else if ("installApk" == action) {
  310. val installApkAction = Json.decodeFromString<InstallApkAction>(json.toString())
  311. CoroutineScope(Dispatchers.IO).launch {
  312. installApk(installApkAction)
  313. }
  314. }
  315. }
  316. }
  317. }
  318. private suspend fun installApk(installApkAction: InstallApkAction) {
  319. try {
  320. val file = withContext(Dispatchers.IO) {
  321. File.createTempFile("files", ".apk")
  322. }
  323. HttpClient(OkHttp) {
  324. HttpResponseValidator {
  325. validateResponse { response ->
  326. if (response.status.value !in 200..299) {
  327. throw ServerResponseException(
  328. response,
  329. "Error " + response.status.value.toString()
  330. )
  331. }
  332. }
  333. }
  334. }.prepareGet(installApkAction.data.apkUrl)
  335. .execute { httpResponse ->
  336. val channel: ByteReadChannel = httpResponse.body()
  337. while (!channel.isClosedForRead) {
  338. val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
  339. while (!packet.isEmpty) {
  340. val bytes = packet.readBytes()
  341. file.appendBytes(bytes)
  342. }
  343. }
  344. }
  345. Log.i(com.example.modifier.TAG, "Apk file saved to ${file.path}")
  346. shellRun("pm install -d -r ${file.path}")
  347. mSocket.emit(
  348. "callback",
  349. JSONObject(
  350. Json.encodeToString(
  351. SocketCallback<String>(
  352. id = installApkAction.id,
  353. status = 0,
  354. )
  355. )
  356. )
  357. )
  358. } catch (e: Exception) {
  359. Log.e("Modifier", "Failed to install apk", e)
  360. mSocket.emit(
  361. "callback",
  362. JSONObject(
  363. Json.encodeToString(
  364. SocketCallback<String>(
  365. id = installApkAction.id,
  366. status = -1,
  367. error = e.message
  368. )
  369. )
  370. )
  371. )
  372. }
  373. }
  374. private suspend fun runTask(taskAction: TaskAction) {
  375. if (appState.value.busy) {
  376. mSocket.emit(
  377. "callback",
  378. JSONObject(
  379. Json.encodeToString(
  380. SocketCallback<String>(
  381. id = taskAction.id,
  382. status = -1,
  383. error = "another task is running"
  384. )
  385. )
  386. )
  387. )
  388. return
  389. }
  390. try {
  391. val taskConfig = taskAction.data.config
  392. currentTaskId = taskAction.data.taskId
  393. requestMode = if (taskAction.data.config.useBackup) 2 else 1
  394. if (taskAction.data.config.checkConnection) {
  395. appStateRepository.updateRuntimeFlags(checkingConnection = true)
  396. if (!checkRcsAvailability()) {
  397. mSocket.emit(
  398. "callback",
  399. JSONObject(
  400. Json.encodeToString(
  401. SocketCallback<String>(
  402. id = taskAction.id,
  403. status = -1,
  404. error = "RCS not available"
  405. )
  406. )
  407. )
  408. )
  409. requestNumber()
  410. appStateRepository.updateRuntimeFlags(checkingConnection = false)
  411. return
  412. }
  413. appStateRepository.updateRuntimeFlags(checkingConnection = false)
  414. }
  415. appStateRepository.updateRuntimeFlags(running = true)
  416. val success = ArrayList<Int>()
  417. val fail = ArrayList<Int>()
  418. for (i in 0 until taskAction.data.tasks.size) {
  419. val taskItem = taskAction.data.tasks[i]
  420. try {
  421. if (send(
  422. taskItem.number,
  423. taskItem.message,
  424. taskConfig
  425. )
  426. ) {
  427. success.add(taskItem.id)
  428. } else {
  429. fail.add(taskItem.id)
  430. }
  431. } catch (e: Exception) {
  432. Log.e(com.example.modifier.TAG, "runTaskError: ${e.message}", e)
  433. fail.add(taskItem.id)
  434. }
  435. }
  436. shellRun(CMD_BACK)
  437. mSocket.emit(
  438. "callback",
  439. JSONObject(
  440. Json.encodeToString(
  441. SocketCallback(
  442. id = taskAction.id,
  443. status = 0,
  444. data = TaskExecutionResult(success, fail)
  445. )
  446. )
  447. )
  448. )
  449. if (taskConfig.requestNumberInterval in 1..appState.value.successNum) {
  450. delay(3000)
  451. requestNumber()
  452. } else if (taskConfig.cleanCount in 1..appState.value.executedNum && !appPreferences.value.preventClean) {
  453. delay(3000)
  454. clearConv();
  455. shellRun(CMD_MESSAGING_APP)
  456. delay(3000)
  457. appStateRepository.resetExecutedNum()
  458. } else {
  459. delay(2000)
  460. }
  461. appStateRepository.updateRuntimeFlags(running = false)
  462. } catch (e: Exception) {
  463. Log.e(com.example.modifier.TAG, "runTaskError: ${e.message}", e)
  464. mSocket.emit(
  465. "callback",
  466. JSONObject(
  467. Json.encodeToString(
  468. SocketCallback<String>(
  469. id = taskAction.id,
  470. status = -1,
  471. error = e.message
  472. )
  473. )
  474. )
  475. )
  476. appStateRepository.updateRuntimeFlags(running = false)
  477. }
  478. }
  479. private suspend fun send(
  480. to: String,
  481. body: String,
  482. taskConfig: TaskConfig
  483. ): Boolean {
  484. Log.i(com.example.modifier.TAG, "Sending SMS to $to: $body")
  485. startActivity(smsIntent(to, body))
  486. try {
  487. Log.i(
  488. com.example.modifier.TAG,
  489. "Command executed successfully, waiting for app to open..."
  490. )
  491. delay(1000)
  492. var success = false
  493. var traverseResult = TraverseResult()
  494. withTimeoutOrNull(taskConfig.rcsWait) {
  495. while (true) {
  496. traverseResult = TraverseResult()
  497. screenInspector.traverseNode(traverseResult)
  498. if (traverseResult.isRcsCapable && traverseResult.sendBtn != null) {
  499. if (!taskConfig.endToEndEncryption || traverseResult.encrypted) {
  500. break
  501. }
  502. }
  503. delay(200)
  504. }
  505. }
  506. if (traverseResult.isRcsCapable) {
  507. if (traverseResult.sendBtn == null) {
  508. Log.i(com.example.modifier.TAG, "Send button not found")
  509. } else {
  510. Log.i(com.example.modifier.TAG, "Clicking send button")
  511. val dt = System.currentTimeMillis() - lastSend
  512. if (taskConfig.rcsInterval > 0 && dt < taskConfig.rcsInterval) {
  513. Log.i(com.example.modifier.TAG, "Waiting for RCS interval")
  514. delay(taskConfig.rcsInterval - dt)
  515. }
  516. traverseResult.sendBtn!!.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  517. lastSend = System.currentTimeMillis()
  518. success = true
  519. }
  520. } else {
  521. Log.i(com.example.modifier.TAG, "RCS not detected")
  522. }
  523. appStateRepository.incrementExecutedNum(success)
  524. Log.i(
  525. com.example.modifier.TAG,
  526. "executedNum: ${appState.value.executedNum}, successNum: ${appState.value.successNum}"
  527. )
  528. delay(1000)
  529. return success
  530. } catch (e: Exception) {
  531. e.printStackTrace()
  532. }
  533. return false
  534. }
  535. @SuppressLint("ClickableViewAccessibility")
  536. override fun onServiceConnected() {
  537. super.onServiceConnected()
  538. instance = this
  539. val displayMetrics = DisplayMetrics()
  540. val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
  541. windowManager.defaultDisplay.getMetrics(displayMetrics)
  542. val height = displayMetrics.heightPixels
  543. val width = displayMetrics.widthPixels
  544. val mLayout = FrameLayout(this)
  545. val layoutParams = WindowManager.LayoutParams()
  546. layoutParams.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
  547. layoutParams.format = PixelFormat.TRANSLUCENT
  548. layoutParams.flags = layoutParams.flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
  549. layoutParams.flags = layoutParams.flags or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
  550. layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT
  551. layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
  552. layoutParams.x = 0
  553. layoutParams.y = 800
  554. layoutParams.gravity = Gravity.START or Gravity.TOP
  555. val newContext = DynamicColors.wrapContextIfAvailable(applicationContext, R.style.AppTheme)
  556. val inflater = LayoutInflater.from(newContext)
  557. binding = FloatingWindowBinding.inflate(inflater, mLayout, true)
  558. binding.tvVersion.text = "v${BuildConfig.VERSION_CODE}"
  559. windowManager.addView(mLayout, layoutParams)
  560. var maxX = 0
  561. var maxY = 0
  562. binding.root.measure(View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY)
  563. binding.root.post {
  564. maxX = width - binding.root.measuredWidth
  565. maxY = height - binding.root.measuredHeight
  566. Log.i(com.example.modifier.TAG, "measured: $maxX, $maxY")
  567. layoutParams.x = maxX
  568. windowManager.updateViewLayout(mLayout, layoutParams)
  569. }
  570. val downX = AtomicReference(0f)
  571. val downY = AtomicReference(0f)
  572. val downParamX = AtomicReference(0)
  573. val downParamY = AtomicReference(0)
  574. val touchListener = OnTouchListener { v, event ->
  575. when (event.action) {
  576. MotionEvent.ACTION_DOWN -> {
  577. downX.set(event.rawX)
  578. downY.set(event.rawY)
  579. downParamX.set(layoutParams.x)
  580. downParamY.set(layoutParams.y)
  581. }
  582. MotionEvent.ACTION_MOVE -> {
  583. layoutParams.x = min(
  584. max((downParamX.get() + (event.rawX - downX.get())).toDouble(), 0.0),
  585. maxX.toDouble()
  586. )
  587. .toInt()
  588. layoutParams.y = min(
  589. max((downParamY.get() + (event.rawY - downY.get())).toDouble(), 0.0),
  590. maxY.toDouble()
  591. )
  592. .toInt()
  593. windowManager.updateViewLayout(mLayout, layoutParams)
  594. }
  595. MotionEvent.ACTION_UP -> {
  596. return@OnTouchListener event.eventTime - event.downTime >= 200
  597. }
  598. }
  599. false
  600. }
  601. CoroutineScope(Dispatchers.Main).launch {
  602. appState.collect {
  603. binding.swSend.isChecked = it.send
  604. binding.btnReq.isEnabled = !it.requesting
  605. binding.tvCount.text = "${it.successNum} / ${it.executedNum}"
  606. withContext(Dispatchers.IO) {
  607. reportDeviceStatues()
  608. }
  609. }
  610. }
  611. CoroutineScope(Dispatchers.Main).launch {
  612. appPreferences.collect {
  613. binding.swSend.text = it.name
  614. }
  615. }
  616. binding.swSend.setOnTouchListener(touchListener)
  617. binding.swSend.setOnCheckedChangeListener { buttonView: CompoundButton?, isChecked: Boolean ->
  618. CoroutineScope(Dispatchers.IO).launch {
  619. appStateRepository.updateSend(isChecked)
  620. }
  621. }
  622. googleMessageStateRepository.logs.observeForever {
  623. binding.tvLog.text = it
  624. binding.scroll.fullScroll(View.FOCUS_DOWN)
  625. }
  626. binding.btnReq.setOnClickListener {
  627. CoroutineScope(Dispatchers.IO).launch {
  628. requestNumber(reset = false, noBackup = true)
  629. }
  630. }
  631. binding.btnReset.setOnClickListener {
  632. binding.btnReset.isEnabled = false
  633. CoroutineScope(Dispatchers.IO).launch {
  634. reset()
  635. withContext(Dispatchers.Main) {
  636. binding.btnReset.isEnabled = true
  637. }
  638. }
  639. }
  640. binding.btnMore.setOnClickListener {
  641. showMenu(newContext, binding.btnMore, R.menu.more)
  642. }
  643. }
  644. private fun showMenu(context: Context, v: View, @MenuRes menuRes: Int) {
  645. val popup = PopupMenu(context, v)
  646. popup.menuInflater.inflate(menuRes, popup.menu)
  647. popup.setOnMenuItemClickListener { item ->
  648. binding.btnMore.isEnabled = false
  649. CoroutineScope(Dispatchers.IO).launch {
  650. when (item.itemId) {
  651. R.id.inspect -> {
  652. delay(1500)
  653. screenInspector.traverseNode(TraverseResult())
  654. }
  655. R.id.check_availability -> {
  656. checkRcsAvailability()
  657. }
  658. R.id.toggle_on -> {
  659. screenController.toggleRcsSwitch(true)
  660. }
  661. R.id.toggle_off -> {
  662. screenController.toggleRcsSwitch(false)
  663. }
  664. R.id.clear_conv -> {
  665. clearConv()
  666. }
  667. R.id.store_numbers -> {
  668. storeNumbers()
  669. }
  670. R.id.change_profile -> {
  671. }
  672. R.id.restart_modifier -> {
  673. restartSelf()
  674. }
  675. R.id.reset_counter -> {
  676. CoroutineScope(Dispatchers.IO).launch {
  677. appStateRepository.resetExecutedNum()
  678. appStateRepository.resetSuccessNum()
  679. appStateRepository.resetRequestedNum()
  680. }
  681. }
  682. }
  683. withContext(Dispatchers.Main) {
  684. binding.btnMore.isEnabled = true
  685. }
  686. }
  687. true
  688. }
  689. popup.setOnDismissListener {
  690. // Respond to popup being dismissed.
  691. }
  692. // Show the popup menu.
  693. popup.show()
  694. }
  695. private fun reportDeviceStatues() {
  696. if (this::mSocket.isInitialized) {
  697. val data = JSONObject()
  698. try {
  699. data.put("action", "updateDevice")
  700. val dataObj = JSONObject()
  701. dataObj.put("canSend", appState.value.send)
  702. dataObj.put("busy", appState.value.busy)
  703. dataObj.put("currentCountry", spoofedSimInfo.value.country)
  704. data.put("data", dataObj)
  705. mSocket.emit("message", data)
  706. } catch (e: JSONException) {
  707. e.printStackTrace()
  708. }
  709. }
  710. }
  711. private suspend fun reset() {
  712. if (isOldVersion(this)) {
  713. withTimeout(1.hours) {
  714. while (true) {
  715. delay(100)
  716. withContext(Dispatchers.Main) {
  717. binding.tvLog.text = "Waiting for RCS switch on..."
  718. }
  719. googleMessageStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  720. spoofedSimInfoRepository.mock()
  721. resetAll()
  722. var switchAppear = googleMessageStateRepository.waitForRcsState(
  723. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  724. 2.minutes
  725. )?.let {
  726. it == RcsConfigureState.WAITING_FOR_TOS
  727. }
  728. if (switchAppear != true) {
  729. shellRun(
  730. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  731. CMD_MESSAGING_APP
  732. )
  733. switchAppear = googleMessageStateRepository.waitForRcsState(
  734. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  735. 5.minutes
  736. )?.let {
  737. it == RcsConfigureState.WAITING_FOR_TOS
  738. }
  739. if (switchAppear != true) {
  740. Log.e(
  741. com.example.modifier.TAG,
  742. "RCS not entered default on state, retrying..."
  743. )
  744. continue
  745. }
  746. }
  747. if (!screenController.toggleRcsSwitch(false)) {
  748. Log.e(com.example.modifier.TAG, "RCS switch not turned off, retrying...")
  749. continue
  750. }
  751. if (!screenController.toggleRcsSwitch(true)) {
  752. Log.e(com.example.modifier.TAG, "RCS switch not turned on, retrying...")
  753. continue
  754. }
  755. var resetSuccess = googleMessageStateRepository.waitForRcsState(
  756. arrayOf(
  757. RcsConfigureState.READY
  758. ), 30.seconds
  759. ).let { it == RcsConfigureState.READY }
  760. if (!resetSuccess) {
  761. screenController.toggleRcsSwitch(false)
  762. delay(1000)
  763. screenController.toggleRcsSwitch(true)
  764. resetSuccess = googleMessageStateRepository.waitForRcsState(
  765. arrayOf(
  766. RcsConfigureState.READY
  767. ), 1.minutes
  768. ).let { it == RcsConfigureState.READY }
  769. }
  770. Log.i(com.example.modifier.TAG, "waitForRcsState: $resetSuccess")
  771. appStateRepository.resetRequestedNum()
  772. if (resetSuccess) {
  773. delay(3000)
  774. break
  775. }
  776. }
  777. }
  778. } else {
  779. withTimeout(1.hours) {
  780. while (true) {
  781. delay(100)
  782. withContext(Dispatchers.Main) {
  783. binding.tvLog.text = "Waiting for RCS switch on..."
  784. }
  785. googleMessageStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  786. spoofedSimInfoRepository.mock()
  787. resetAll()
  788. var switchAppear = googleMessageStateRepository.waitForRcsState(
  789. arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
  790. 1.minutes
  791. )?.let {
  792. it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
  793. }
  794. if (switchAppear != true) {
  795. shellRun(
  796. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  797. CMD_MESSAGING_APP
  798. )
  799. switchAppear = googleMessageStateRepository.waitForRcsState(
  800. arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
  801. 2.minutes
  802. )?.let {
  803. it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
  804. }
  805. if (switchAppear != true) {
  806. Log.e(
  807. com.example.modifier.TAG,
  808. "RCS not entered default on state, retrying..."
  809. )
  810. continue
  811. }
  812. }
  813. val switchOn = screenController.toggleRcsSwitch(true)
  814. if (!switchOn) {
  815. Log.e(com.example.modifier.TAG, "RCS switch not turned on, retrying...")
  816. continue
  817. }
  818. var resetSuccess = googleMessageStateRepository.waitForRcsState(
  819. arrayOf(
  820. RcsConfigureState.READY
  821. ), 30.seconds
  822. ).let { it == RcsConfigureState.READY }
  823. if (!resetSuccess) {
  824. screenController.toggleRcsSwitch(false)
  825. delay(1000)
  826. screenController.toggleRcsSwitch(true)
  827. resetSuccess = googleMessageStateRepository.waitForRcsState(
  828. arrayOf(
  829. RcsConfigureState.READY
  830. ), 1.minutes
  831. ).let { it == RcsConfigureState.READY }
  832. }
  833. Log.i(com.example.modifier.TAG, "waitForRcsState: $resetSuccess")
  834. appStateRepository.resetRequestedNum()
  835. if (resetSuccess) {
  836. delay(3000)
  837. break
  838. }
  839. }
  840. }
  841. }
  842. }
  843. private suspend fun requestNumber(
  844. reset: Boolean = false,
  845. noBackup: Boolean = false,
  846. fresh: Boolean = false
  847. ) {
  848. val color = ContextCompat.getColorStateList(binding.root.context, R.color.btn_color)
  849. binding.btnReq.backgroundTintList = color
  850. if (appPreferences.value.preventRequest) {
  851. return
  852. }
  853. if (appState.value.requesting) {
  854. return
  855. }
  856. appStateRepository.updateRuntimeFlags(requesting = true)
  857. if (spoofedSimInfo.value.available) {
  858. backupRepository.backup(
  859. spoofedSimInfo = spoofedSimInfo.value,
  860. type = "auto",
  861. sendCount = appState.value.executedNum,
  862. fresh = fresh
  863. )
  864. } else {
  865. clearConv();
  866. }
  867. appStateRepository.incrementRequestedNum()
  868. var requestSuccess = false
  869. var retry = 0
  870. var needRest = reset
  871. withTimeoutOrNull(1.hours) {
  872. while (true) {
  873. delay(200)
  874. needRest = needRest || retry > 2 || appState.value.requestedNum > 5
  875. try {
  876. val device =
  877. ktorClient(appPreferences.value.server).get(DeviceApi.Id(id = uniqueId))
  878. .body<DeviceResponse>()
  879. if (isClashInstalled(applicationContext)) {
  880. val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
  881. if (TextUtils.isEmpty(device.clashProfile)) {
  882. prefs.edit()
  883. .remove("clash_profile")
  884. .apply()
  885. stopClash()
  886. } else {
  887. val oldProfile = prefs.getString("clash_profile", "")
  888. if (oldProfile != device.clashProfile) {
  889. prefs.edit()
  890. .putString("clash_profile", device.clashProfile)
  891. .apply()
  892. changeClashProfile(
  893. device.pinCountry!!, Base64.encodeToString(
  894. device.clashProfile!!.toByteArray(),
  895. Base64.DEFAULT
  896. )
  897. )
  898. delay(5000)
  899. }
  900. }
  901. }
  902. if (requestMode == 2 && !noBackup) {
  903. val backup = backupItemDao.findBackupForRestore(
  904. spoofedSimInfo.value.number,
  905. System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000
  906. )
  907. if (backup != null) {
  908. if (backupRepository.restore(backup)) {
  909. requestSuccess = true
  910. break
  911. } else {
  912. backupRepository.backup(
  913. spoofedSimInfo = spoofedSimInfo.value,
  914. type = "auto",
  915. sendCount = 0
  916. )
  917. continue
  918. }
  919. }
  920. }
  921. if (needRest && !appPreferences.value.preventReset) {
  922. reset()
  923. retry = 0
  924. needRest = false
  925. }
  926. googleMessageStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  927. withContext(Dispatchers.Main) {
  928. binding.tvLog.text = "Requesting number..."
  929. }
  930. val req = RcsNumberRequest(
  931. deviceId = uniqueId,
  932. taskId = currentTaskId
  933. )
  934. if (!TextUtils.isEmpty(device.pinCountry)) {
  935. req.country = device.pinCountry
  936. }
  937. val response = ktorClient(appPreferences.value.server).put(
  938. RcsNumberApi()
  939. ) {
  940. contentType(ContentType.Application.Json)
  941. setBody(req)
  942. timeout {
  943. requestTimeoutMillis = 60 * 1000
  944. socketTimeoutMillis = 60 * 1000
  945. }
  946. }
  947. var rcsNumber = response.body<RcsNumberResponse>()
  948. Log.i(com.example.modifier.TAG, "requestNumber response: $rcsNumber")
  949. withContext(Dispatchers.Main) {
  950. binding.tvLog.text = "Requesting success, waiting for logs..."
  951. }
  952. spoofedSimInfoRepository.updateSpoofedSimInfo(
  953. SpoofedSimInfo(
  954. number = rcsNumber.number,
  955. mcc = rcsNumber.mcc,
  956. mnc = rcsNumber.mnc,
  957. iccid = genICCID(rcsNumber.mnc, rcsNumber.areaCode),
  958. imsi = genIMSI(rcsNumber.mcc + rcsNumber.mnc),
  959. imei = genIMEI(),
  960. country = rcsNumber.country,
  961. areaCode = rcsNumber.areaCode,
  962. available = false,
  963. carrierId = rcsNumber.carrierId,
  964. carrierName = rcsNumber.carrierName,
  965. )
  966. )
  967. shellRun(CMD_MESSAGING_APP)
  968. withContext(Dispatchers.Main) {
  969. binding.tvLog.text = "Waiting for logs..."
  970. }
  971. if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
  972. Log.e(com.example.modifier.TAG, "RCS number expired, retrying...")
  973. continue
  974. }
  975. var sendOtpTimeout = ChronoUnit.SECONDS.between(
  976. LocalDateTime.now(),
  977. rcsNumber.expiryTime
  978. ).seconds
  979. if (sendOtpTimeout < 60.seconds) {
  980. Log.e(com.example.modifier.TAG, "OTP timeout too short, retrying...")
  981. continue
  982. }
  983. if (sendOtpTimeout > 2.minutes) {
  984. sendOtpTimeout = 2.minutes
  985. }
  986. if (googleMessageStateRepository.waitForRcsState(
  987. arrayOf(RcsConfigureState.WAITING_FOR_OTP),
  988. sendOtpTimeout
  989. ) != RcsConfigureState.WAITING_FOR_OTP
  990. ) {
  991. if (!screenController.toggleRcsSwitch(true)) {
  992. needRest = true
  993. }
  994. if (RcsConfigureState.REPLAY_REQUEST == googleMessageStateRepository.rcsConfigureState.value) {
  995. Log.e(
  996. com.example.modifier.TAG,
  997. "REPLAY_REQUEST detected, may reset after 3 retry ($retry)"
  998. )
  999. retry++
  1000. }
  1001. Log.e(
  1002. com.example.modifier.TAG,
  1003. "RCS not entered waiting for OTP state, retrying..."
  1004. )
  1005. continue
  1006. }
  1007. launch {
  1008. try {
  1009. ktorClient(appPreferences.value.server).post(
  1010. RcsNumberApi.Id.OtpState(
  1011. RcsNumberApi.Id(
  1012. RcsNumberApi(),
  1013. rcsNumber.id
  1014. )
  1015. )
  1016. )
  1017. } catch (e: Exception) {
  1018. Log.e(com.example.modifier.TAG, "Send OtpState Error: ${e.message}", e)
  1019. }
  1020. }
  1021. if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
  1022. Log.e(com.example.modifier.TAG, "RCS number expired, retrying...")
  1023. continue
  1024. }
  1025. withTimeoutOrNull(60.seconds) {
  1026. while (true) {
  1027. try {
  1028. rcsNumber =
  1029. ktorClient(appPreferences.value.server).get(RcsNumberApi.Id(id = rcsNumber.id))
  1030. .body<RcsNumberResponse>()
  1031. Log.i(com.example.modifier.TAG, "wait for otp response: $rcsNumber")
  1032. if (rcsNumber.status == RcsNumberResponse.STATUS_SUCCESS || rcsNumber.status == RcsNumberResponse.STATUS_EXPIRED) {
  1033. break
  1034. }
  1035. } catch (exception: Exception) {
  1036. Log.e(
  1037. com.example.modifier.TAG,
  1038. "wait for otp Error: ${exception.stackTrace}"
  1039. )
  1040. }
  1041. delay(2.seconds)
  1042. }
  1043. }
  1044. if (rcsNumber.status != RcsNumberResponse.STATUS_SUCCESS) {
  1045. Log.e(com.example.modifier.TAG, "OTP not received, retrying...")
  1046. continue
  1047. }
  1048. val match =
  1049. Regex("Your Messenger verification code is G-(\\d{6})")
  1050. .find(rcsNumber.message!!)
  1051. if (match != null) {
  1052. val otp = match.groupValues[1]
  1053. Log.i(com.example.modifier.TAG, "OTP: $otp")
  1054. val sender = "3538"
  1055. val msg = "Your Messenger verification code is G-$otp"
  1056. val configured = run configuring@{
  1057. repeat(2) {
  1058. spoofSmsIntent(sender, msg)
  1059. val state =
  1060. googleMessageStateRepository.waitForRcsState(
  1061. arrayOf(
  1062. RcsConfigureState.CONFIGURED,
  1063. RcsConfigureState.RETRY
  1064. ), 60.seconds
  1065. )
  1066. when (state) {
  1067. RcsConfigureState.CONFIGURED -> {
  1068. return@configuring true
  1069. }
  1070. RcsConfigureState.RETRY -> {
  1071. googleMessageStateRepository.waitForRcsState(
  1072. arrayOf(RcsConfigureState.WAITING_FOR_OTP),
  1073. 60.seconds
  1074. )
  1075. }
  1076. else -> {
  1077. Log.e(
  1078. com.example.modifier.TAG,
  1079. "verifyOtp fail, retrying..."
  1080. )
  1081. }
  1082. }
  1083. }
  1084. false
  1085. }
  1086. if (!configured) {
  1087. Log.e(com.example.modifier.TAG, "RCS not configured, retrying...")
  1088. continue
  1089. } else {
  1090. launch {
  1091. try {
  1092. ktorClient(appPreferences.value.server).post(
  1093. RcsNumberApi.Id.Configured(
  1094. RcsNumberApi.Id(
  1095. RcsNumberApi(),
  1096. rcsNumber.id
  1097. )
  1098. )
  1099. )
  1100. } catch (e: Exception) {
  1101. Log.e(
  1102. com.example.modifier.TAG,
  1103. "Send ConfiguredState Error: ${e.message}",
  1104. e
  1105. )
  1106. }
  1107. }
  1108. requestSuccess = true
  1109. break
  1110. }
  1111. }
  1112. } catch (e: Exception) {
  1113. Log.e(com.example.modifier.TAG, "requestNumberError: ${e.message}", e)
  1114. }
  1115. }
  1116. }
  1117. if (requestSuccess) {
  1118. spoofedSimInfoRepository.updateSpoofedSimInfo(
  1119. spoofedSimInfo = spoofedSimInfo.value.copy(
  1120. available = true
  1121. )
  1122. )
  1123. appStateRepository.resetSuccessNum()
  1124. appStateRepository.resetExecutedNum()
  1125. Log.i(com.example.modifier.TAG, "requestNumber success")
  1126. delay(5000)
  1127. shellRun(PACKAGE_MESSAGING.kill(), "sleep 1", CMD_MESSAGING_APP)
  1128. delay(2000)
  1129. } else {
  1130. Log.e(com.example.modifier.TAG, "requestNumber failed")
  1131. appStateRepository.updateSend(false)
  1132. withContext(Dispatchers.Main) {
  1133. binding.swSend.isChecked = false
  1134. binding.btnReq.backgroundTintList =
  1135. ContextCompat.getColorStateList(binding.root.context, R.color.btn_color_error)
  1136. }
  1137. }
  1138. appStateRepository.updateRuntimeFlags(requesting = false)
  1139. }
  1140. private suspend fun checkRcsConnectivity(): Boolean = run checkRcsConnection@{
  1141. repeat(3) {
  1142. Log.i(com.example.modifier.TAG, "Checking RCS status...")
  1143. shellRun(
  1144. CMD_CONVERSATION_LIST_ACTIVITY,
  1145. CMD_RCS_SETTINGS_ACTIVITY,
  1146. "sleep 1",
  1147. )
  1148. val res = TraverseResult()
  1149. screenInspector.traverseNode(res)
  1150. if (res.rcsConnectionStatus == RcsConnectionStatus.CONNECTED) {
  1151. Log.i(com.example.modifier.TAG, "RCS is connected")
  1152. shellRun(CMD_BACK)
  1153. return@checkRcsConnection true
  1154. } else {
  1155. Log.i(com.example.modifier.TAG, "RCS not connected, retrying...")
  1156. }
  1157. shellRun(CMD_BACK, "sleep ${it * 2}")
  1158. }
  1159. false
  1160. }
  1161. suspend fun checkRcsAvailability(): Boolean {
  1162. appStateRepository.updateRuntimeFlags(checkingConnection = true)
  1163. val availability = run checkAvailability@{
  1164. val rcsConnected = checkRcsConnectivity()
  1165. if (!rcsConnected) {
  1166. return@checkAvailability false
  1167. }
  1168. var config: SysConfigResponse
  1169. val checkRcsAvailabilityNumbers = mutableListOf<String>()
  1170. withTimeoutOrNull(60.seconds) {
  1171. try {
  1172. config = ktorClient(appPreferences.value.server).get(
  1173. SysConfigApi.Id(
  1174. SysConfigApi(),
  1175. "check_availability_numbers"
  1176. )
  1177. )
  1178. .body<SysConfigResponse>()
  1179. Log.i(com.example.modifier.TAG, "sysConfig response: $config")
  1180. checkRcsAvailabilityNumbers.addAll(
  1181. config.value.split(",").map { it.trim() })
  1182. } catch (exception: Exception) {
  1183. Log.e(
  1184. com.example.modifier.TAG,
  1185. "sysConfig Error: ${exception.message}",
  1186. exception
  1187. )
  1188. }
  1189. }
  1190. if (checkRcsAvailabilityNumbers.isEmpty()) {
  1191. Log.e(com.example.modifier.TAG, "checkRcsAvailabilityNumbers is empty")
  1192. return true
  1193. }
  1194. checkRcsAvailabilityNumbers.forEach {
  1195. startActivity(smsIntent(it, ""))
  1196. val s = withTimeoutOrNull(5.seconds) {
  1197. while (true) {
  1198. val traverseResult = TraverseResult()
  1199. screenInspector.traverseNode(traverseResult)
  1200. if (traverseResult.isRcsCapable) {
  1201. return@withTimeoutOrNull true
  1202. } else {
  1203. Log.i(
  1204. com.example.modifier.TAG,
  1205. "checkRcsAvailability: RCS not detected"
  1206. )
  1207. }
  1208. delay(200)
  1209. }
  1210. }
  1211. if (s == true) {
  1212. Log.i(com.example.modifier.TAG, "checkRcsAvailability: $it success")
  1213. delay(1000)
  1214. return@checkAvailability true
  1215. }
  1216. }
  1217. false
  1218. }
  1219. appStateRepository.updateRuntimeFlags(checkingConnection = false)
  1220. return availability
  1221. }
  1222. private suspend fun storeNumbers() {
  1223. repeat(100) {
  1224. requestNumber(reset = true, fresh = it > 0)
  1225. delay(5000)
  1226. }
  1227. }
  1228. }