ModifierService.kt 52 KB

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