TaskRunner.kt 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. package com.example.modifier.service
  2. import android.content.Context
  3. import android.util.Log
  4. import android.view.accessibility.AccessibilityNodeInfo
  5. import coil3.ImageLoader
  6. import coil3.SingletonImageLoader
  7. import coil3.request.ImageRequest
  8. import coil3.request.crossfade
  9. import com.example.modifier.baseTag
  10. import com.example.modifier.TraverseResult
  11. import com.example.modifier.constants.CMD_BACK
  12. import com.example.modifier.constants.CMD_CONVERSATION_LIST_ACTIVITY
  13. import com.example.modifier.constants.CMD_MESSAGING_APP
  14. import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY
  15. import com.example.modifier.constants.PACKAGE_GMS
  16. import com.example.modifier.constants.PACKAGE_MESSAGING
  17. import com.example.modifier.enums.RcsConfigureState
  18. import com.example.modifier.enums.RcsConnectionStatus
  19. import com.example.modifier.enums.ReqState
  20. import com.example.modifier.exception.RequestNumberException
  21. import com.example.modifier.exception.RequestNumberException.Companion.ErrorCode
  22. import com.example.modifier.extension.kill
  23. import com.example.modifier.http.api.DeviceApi
  24. import com.example.modifier.http.api.RcsNumberApi
  25. import com.example.modifier.http.api.SysConfigApi
  26. import com.example.modifier.http.downloadImage
  27. import com.example.modifier.http.ktorClient
  28. import com.example.modifier.http.response.SysConfigResponse
  29. import com.example.modifier.model.InstallApkAction
  30. import com.example.modifier.model.RunScriptAction
  31. import com.example.modifier.model.SpoofedSimInfo
  32. import com.example.modifier.model.TaskAction
  33. import com.example.modifier.model.TaskConfig
  34. import com.example.modifier.model.TaskExecutionResult
  35. import com.example.modifier.model.UpdateDeviceAction
  36. import com.example.modifier.repo.AppPrefsRepo
  37. import com.example.modifier.repo.AppStateRepo
  38. import com.example.modifier.repo.BackupRepository
  39. import com.example.modifier.repo.GmsgStateRepository
  40. import com.example.modifier.repo.SpoofedSimInfoRepo
  41. import com.example.modifier.service.ModifierService.Companion
  42. import com.example.modifier.utils.clearConv
  43. import com.example.modifier.utils.genICCID
  44. import com.example.modifier.utils.genIMEI
  45. import com.example.modifier.utils.genIMSI
  46. import com.example.modifier.utils.isOldVersion
  47. import com.example.modifier.utils.resetAll
  48. import com.example.modifier.utils.shellRun
  49. import com.example.modifier.utils.smsIntent
  50. import com.example.modifier.utils.injectOTP
  51. import io.ktor.client.HttpClient
  52. import io.ktor.client.call.body
  53. import io.ktor.client.engine.okhttp.OkHttp
  54. import io.ktor.client.plugins.HttpResponseValidator
  55. import io.ktor.client.plugins.ServerResponseException
  56. import io.ktor.client.plugins.resources.get
  57. import io.ktor.client.request.prepareGet
  58. import io.ktor.utils.io.ByteReadChannel
  59. import io.ktor.utils.io.core.isEmpty
  60. import io.ktor.utils.io.core.readBytes
  61. import kotlinx.coroutines.CancellationException
  62. import kotlinx.coroutines.CoroutineScope
  63. import kotlinx.coroutines.Dispatchers
  64. import kotlinx.coroutines.Job
  65. import kotlinx.coroutines.cancel
  66. import kotlinx.coroutines.coroutineScope
  67. import kotlinx.coroutines.delay
  68. import kotlinx.coroutines.isActive
  69. import kotlinx.coroutines.launch
  70. import kotlinx.coroutines.suspendCancellableCoroutine
  71. import kotlinx.coroutines.withContext
  72. import kotlinx.coroutines.withTimeout
  73. import kotlinx.coroutines.withTimeoutOrNull
  74. import java.io.File
  75. import java.time.LocalDateTime
  76. import java.time.temporal.ChronoUnit
  77. import kotlin.coroutines.coroutineContext
  78. import kotlin.time.Duration.Companion.hours
  79. import kotlin.time.Duration.Companion.minutes
  80. import kotlin.time.Duration.Companion.seconds
  81. class TaskRunner(
  82. private val context: Context,
  83. private val screenInspector: ScreenInspector,
  84. val screenController: ScreenController,
  85. private val appStateRepo: AppStateRepo,
  86. private val appPrefsRepo: AppPrefsRepo,
  87. private val spoofedSimInfoRepo: SpoofedSimInfoRepo,
  88. val gmsgStateRepository: GmsgStateRepository,
  89. private val backupRepository: BackupRepository
  90. ) {
  91. companion object {
  92. private const val TAG = "$baseTag/TaskRunner"
  93. }
  94. private var lastSend = 0L
  95. private var currentTaskId = 0
  96. private var requestMode = 1
  97. private var storeNumberJob: Job? = null
  98. private val imageLoader = ImageLoader.Builder(context)
  99. .crossfade(true)
  100. .build()
  101. suspend fun send(
  102. to: String,
  103. body: String?,
  104. img: String?,
  105. taskConfig: TaskConfig
  106. ): Boolean {
  107. Log.i(TAG, "Sending SMS to $to: $body")
  108. var imgFile: File? = null
  109. if (img?.isNotBlank() == true) {
  110. imgFile = downloadImage(img)
  111. }
  112. context.startActivity(smsIntent(to, body, imgFile))
  113. try {
  114. Log.i(TAG, "Command executed successfully, waiting for app to open...")
  115. delay(1000)
  116. var success = false
  117. var traverseResult = TraverseResult()
  118. withTimeoutOrNull(taskConfig.rcsWait) {
  119. repeat(999) {
  120. traverseResult = TraverseResult()
  121. screenInspector.traverseNode(traverseResult)
  122. if (traverseResult.isRcsCapable && traverseResult.sendBtn != null) {
  123. return@withTimeoutOrNull
  124. }
  125. delay(200)
  126. }
  127. }
  128. if (traverseResult.isRcsCapable && traverseResult.sendBtn != null && taskConfig.e2ee > 0) {
  129. withTimeoutOrNull(taskConfig.e2eeTimeout) {
  130. repeat(999) {
  131. traverseResult = TraverseResult()
  132. screenInspector.traverseNode(traverseResult)
  133. if (traverseResult.encrypted) {
  134. return@withTimeoutOrNull
  135. }
  136. delay(200)
  137. }
  138. }
  139. }
  140. if (traverseResult.isRcsCapable) {
  141. if (traverseResult.sendBtn == null) {
  142. Log.i(TAG, "Send button not found")
  143. } else if (taskConfig.e2ee == 2 && !traverseResult.encrypted) {
  144. Log.i(TAG, "E2EE not detected")
  145. } else {
  146. Log.i(TAG, "Clicking send button")
  147. val dt = System.currentTimeMillis() - lastSend
  148. if (taskConfig.rcsInterval > 0 && dt < taskConfig.rcsInterval) {
  149. Log.i(TAG, "Waiting for RCS interval")
  150. delay(taskConfig.rcsInterval - dt)
  151. }
  152. traverseResult.sendBtn!!.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  153. lastSend = System.currentTimeMillis()
  154. success = true
  155. }
  156. } else {
  157. Log.i(TAG, "RCS not detected")
  158. }
  159. appStateRepo.incrementExecutedNum(success)
  160. Log.i(
  161. TAG,
  162. "executedNum: ${appStateRepo.appState.value.executedNum}, successNum: ${appStateRepo.appState.value.successNum}"
  163. )
  164. delay(1000)
  165. return success
  166. } catch (e: Exception) {
  167. e.printStackTrace()
  168. }
  169. return false
  170. }
  171. suspend fun runTask(
  172. taskAction: TaskAction,
  173. onSuccess: (TaskExecutionResult) -> Unit,
  174. onError: (Exception) -> Unit
  175. ) {
  176. if (appStateRepo.appState.value.busy) {
  177. onError(Exception("device busy"))
  178. return
  179. }
  180. try {
  181. val taskConfig = taskAction.data.config
  182. currentTaskId = taskAction.data.taskId
  183. requestMode = if (taskAction.data.config.useBackup) 2 else 1
  184. if (!spoofedSimInfoRepo.spoofedSimInfo.value.available ||
  185. (taskAction.data.config.checkConnection && appStateRepo.appState.value.executedNum == 0)
  186. ) {
  187. appStateRepo.updateRuntimeFlags(checkingConnection = true)
  188. if (!spoofedSimInfoRepo.spoofedSimInfo.value.available || !checkRcsA10y()) {
  189. onError(Exception("RCS not available"))
  190. requestNumberOnTask()
  191. appStateRepo.updateRuntimeFlags(checkingConnection = false)
  192. return
  193. }
  194. appStateRepo.updateRuntimeFlags(checkingConnection = false)
  195. }
  196. appStateRepo.updateRuntimeFlags(running = true, checkingConnection = false)
  197. val success = ArrayList<Int>()
  198. val fail = ArrayList<Int>()
  199. for (i in 0 until taskAction.data.tasks.size) {
  200. val taskItem = taskAction.data.tasks[i]
  201. try {
  202. if (send(taskItem.number, taskItem.message, taskItem.img, taskConfig)) {
  203. success.add(taskItem.id)
  204. } else {
  205. fail.add(taskItem.id)
  206. }
  207. } catch (e: Exception) {
  208. Log.e(TAG, "runTaskError: ${e.message}", e)
  209. fail.add(taskItem.id)
  210. }
  211. }
  212. shellRun(CMD_BACK)
  213. onSuccess(TaskExecutionResult(success, fail))
  214. if (taskConfig.requestNumberInterval in 1..appStateRepo.appState.value.successNum) {
  215. delay(3000)
  216. requestNumberOnTask()
  217. } else if (taskConfig.cleanCount in 1..appStateRepo.appState.value.executedNum && !appPrefsRepo.appPrefs.value.preventClean) {
  218. delay(3000)
  219. clearConv();
  220. shellRun(CMD_MESSAGING_APP)
  221. delay(3000)
  222. appStateRepo.resetExecutedNum()
  223. } else {
  224. delay(2000)
  225. }
  226. appStateRepo.updateRuntimeFlags(running = false)
  227. if (taskAction.data.config.checkConnection && success.isEmpty()) {
  228. appStateRepo.updateRuntimeFlags(checkingConnection = true)
  229. if (!checkRcsA10y()) {
  230. onError(Exception("RCS not available"))
  231. requestNumberOnTask()
  232. }
  233. appStateRepo.updateRuntimeFlags(checkingConnection = false)
  234. }
  235. } catch (e: Exception) {
  236. Log.e(TAG, "runTaskError: ${e.message}", e)
  237. onError(e)
  238. appStateRepo.updateRuntimeFlags(running = false)
  239. }
  240. }
  241. suspend fun reset() {
  242. if (isOldVersion(context)) {
  243. withTimeout(1.hours) {
  244. while (true) {
  245. delay(100)
  246. appStateRepo.updateRuntimeFlags(reqState = ReqState.RESET)
  247. gmsgStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  248. spoofedSimInfoRepo.mock()
  249. resetAll()
  250. var switchAppear = gmsgStateRepository.waitForRcsState(
  251. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  252. 2.minutes
  253. )?.let {
  254. it == RcsConfigureState.WAITING_FOR_TOS
  255. }
  256. if (switchAppear != true) {
  257. shellRun(
  258. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  259. CMD_MESSAGING_APP
  260. )
  261. switchAppear = gmsgStateRepository.waitForRcsState(
  262. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  263. 5.minutes
  264. )?.let {
  265. it == RcsConfigureState.WAITING_FOR_TOS
  266. }
  267. if (switchAppear != true) {
  268. Log.e(TAG, "RCS not entered default on state, retrying...")
  269. continue
  270. }
  271. }
  272. if (!screenController.toggleRcsSwitch(false)) {
  273. Log.e(TAG, "RCS switch not turned off, retrying...")
  274. continue
  275. }
  276. if (!screenController.toggleRcsSwitch(true)) {
  277. Log.e(TAG, "RCS switch not turned on, retrying...")
  278. continue
  279. }
  280. var resetSuccess = gmsgStateRepository.waitForRcsState(
  281. arrayOf(
  282. RcsConfigureState.READY
  283. ), 30.seconds
  284. ).let { it == RcsConfigureState.READY }
  285. if (!resetSuccess) {
  286. screenController.toggleRcsSwitch(false)
  287. delay(1000)
  288. screenController.toggleRcsSwitch(true)
  289. resetSuccess = gmsgStateRepository.waitForRcsState(
  290. arrayOf(
  291. RcsConfigureState.READY
  292. ), 1.minutes
  293. ).let { it == RcsConfigureState.READY }
  294. }
  295. Log.i(TAG, "waitForRcsState: $resetSuccess")
  296. appStateRepo.resetRequestedNum()
  297. if (resetSuccess) {
  298. delay(3000)
  299. break
  300. }
  301. }
  302. }
  303. } else {
  304. withTimeout(1.hours) {
  305. while (true) {
  306. delay(100)
  307. appStateRepo.updateRuntimeFlags(reqState = ReqState.RESET)
  308. gmsgStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  309. spoofedSimInfoRepo.mock()
  310. resetAll()
  311. var switchAppear = gmsgStateRepository.waitForRcsState(
  312. arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
  313. 1.minutes
  314. )?.let {
  315. it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
  316. }
  317. if (switchAppear != true) {
  318. shellRun(
  319. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  320. CMD_MESSAGING_APP
  321. )
  322. switchAppear = gmsgStateRepository.waitForRcsState(
  323. arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
  324. 2.minutes
  325. )?.let {
  326. it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
  327. }
  328. if (switchAppear != true) {
  329. Log.e(TAG, "RCS not entered default on state, retrying...")
  330. continue
  331. }
  332. }
  333. val switchOn = screenController.toggleRcsSwitch(true)
  334. if (!switchOn) {
  335. Log.e(TAG, "RCS switch not turned on, retrying...")
  336. continue
  337. }
  338. var resetSuccess = gmsgStateRepository.waitForRcsState(
  339. arrayOf(
  340. RcsConfigureState.READY
  341. ), 30.seconds
  342. ).let { it == RcsConfigureState.READY }
  343. if (!resetSuccess) {
  344. screenController.toggleRcsSwitch(false)
  345. delay(1000)
  346. screenController.toggleRcsSwitch(true)
  347. resetSuccess = gmsgStateRepository.waitForRcsState(
  348. arrayOf(
  349. RcsConfigureState.READY
  350. ), 1.minutes
  351. ).let { it == RcsConfigureState.READY }
  352. }
  353. Log.i(TAG, "waitForRcsState: $resetSuccess")
  354. appStateRepo.resetRequestedNum()
  355. if (resetSuccess) {
  356. delay(1000)
  357. break
  358. }
  359. }
  360. }
  361. }
  362. appStateRepo.updateRuntimeFlags(reqState = ReqState.NONE)
  363. }
  364. private suspend fun requestNumberAtomic(store: Boolean? = false) {
  365. appStateRepo.updateRuntimeFlags(reqState = ReqState.REQUEST)
  366. gmsgStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  367. val device = DeviceApi.getDevice(appPrefsRepo.appPrefs.value.id)
  368. val rcsNumber = RcsNumberApi.getRcsNumber(
  369. deviceId = appPrefsRepo.appPrefs.value.id,
  370. taskId = currentTaskId,
  371. pinCountry = device.pinCountry,
  372. store = store
  373. )
  374. Log.i(TAG, "requestNumber response: $rcsNumber")
  375. appStateRepo.updateRuntimeFlags(reqState = ReqState.OTP_1)
  376. spoofedSimInfoRepo.updateSpoofedSimInfo(
  377. SpoofedSimInfo(
  378. numberId = rcsNumber.id,
  379. number = rcsNumber.number,
  380. mcc = rcsNumber.mcc,
  381. mnc = rcsNumber.mnc,
  382. iccid = genICCID(rcsNumber.mnc, rcsNumber.areaCode),
  383. imsi = genIMSI(rcsNumber.mcc + rcsNumber.mnc),
  384. imei = genIMEI(),
  385. country = rcsNumber.country,
  386. areaCode = rcsNumber.areaCode,
  387. available = false,
  388. carrierId = rcsNumber.carrierId,
  389. carrierName = rcsNumber.carrierName,
  390. )
  391. )
  392. shellRun(CMD_MESSAGING_APP)
  393. if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
  394. throw RequestNumberException(ErrorCode.CODE_NUMBER_EXPIRED)
  395. }
  396. val tosAgreeJob = CoroutineScope(coroutineContext).launch {
  397. run tos@{
  398. repeat(60 * 1000 / 200) {
  399. delay(500)
  400. val traverseResult = TraverseResult()
  401. screenInspector.traverseNode(traverseResult)
  402. if (traverseResult.tosAgreeBtn != null) {
  403. traverseResult.tosAgreeBtn!!.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  404. return@tos
  405. }
  406. }
  407. }
  408. }
  409. var sendOtpTimeout =
  410. ChronoUnit.SECONDS.between(LocalDateTime.now(), rcsNumber.expiryTime).seconds
  411. if (sendOtpTimeout < 5.seconds) {
  412. throw RequestNumberException(ErrorCode.CODE_TIMEOUT_TOO_SHORT)
  413. }
  414. if (sendOtpTimeout > 2.minutes) {
  415. sendOtpTimeout = 2.minutes
  416. }
  417. if (gmsgStateRepository.waitForRcsState(
  418. arrayOf(RcsConfigureState.WAITING_FOR_OTP),
  419. sendOtpTimeout
  420. ) != RcsConfigureState.WAITING_FOR_OTP
  421. ) {
  422. tosAgreeJob.cancel()
  423. if (!screenController.toggleRcsSwitch(true)) {
  424. throw RequestNumberException(ErrorCode.CODE_RCS_TOGGLED_OFF)
  425. }
  426. if (RcsConfigureState.REPLAY_REQUEST == gmsgStateRepository.rcsConfigureState.value) {
  427. throw RequestNumberException(ErrorCode.CODE_REPLAY_RETRY)
  428. }
  429. throw RequestNumberException(ErrorCode.CODE_OTP_NOT_SENT)
  430. }
  431. tosAgreeJob.cancel()
  432. RcsNumberApi.notifyOtpState(rcsNumber.id)
  433. if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
  434. throw RequestNumberException(ErrorCode.CODE_NUMBER_EXPIRED)
  435. }
  436. appStateRepo.updateRuntimeFlags(reqState = ReqState.OTP_2)
  437. val otp = RcsNumberApi.waitForOtp(rcsNumber.id)
  438. ?: throw RequestNumberException(ErrorCode.CODE_OTP_NOT_RECEIVED)
  439. appStateRepo.updateRuntimeFlags(reqState = ReqState.CONFIG)
  440. val configured = run configuring@{
  441. repeat(2) {
  442. injectOTP(otp)
  443. val state =
  444. gmsgStateRepository.waitForRcsState(
  445. arrayOf(
  446. RcsConfigureState.CONFIGURED,
  447. RcsConfigureState.RETRY
  448. ), 60.seconds
  449. )
  450. when (state) {
  451. RcsConfigureState.CONFIGURED -> {
  452. return@configuring true
  453. }
  454. RcsConfigureState.RETRY -> {
  455. gmsgStateRepository.waitForRcsState(
  456. arrayOf(RcsConfigureState.WAITING_FOR_OTP),
  457. 60.seconds
  458. )
  459. }
  460. else -> {
  461. }
  462. }
  463. }
  464. false
  465. }
  466. if (!configured) {
  467. throw RequestNumberException(ErrorCode.CODE_OTP_VERIFY_FAILED)
  468. } else {
  469. RcsNumberApi.notifyConfigured(rcsNumber.id)
  470. delay(5000)
  471. shellRun(PACKAGE_MESSAGING.kill(), "sleep 1", CMD_MESSAGING_APP)
  472. delay(2000)
  473. }
  474. }
  475. suspend fun requestNumberOnTask(reset: Boolean = false, noBackup: Boolean = false) {
  476. appStateRepo.updateRuntimeFlags(suspended = false)
  477. if (appPrefsRepo.appPrefs.value.preventRequest) {
  478. return
  479. }
  480. if (appStateRepo.appState.value.reqState != ReqState.NONE) {
  481. return
  482. }
  483. appStateRepo.updateRuntimeFlags(reqState = ReqState.CLEAN)
  484. clearConv()
  485. if (spoofedSimInfoRepo.spoofedSimInfo.value.available) {
  486. backupRepository.backup(
  487. type = "auto",
  488. sendCount = appStateRepo.appState.value.successNum
  489. )
  490. }
  491. var needRest = reset
  492. val requestSuccess = withTimeoutOrNull(2.hours) {
  493. while (true) {
  494. delay(200)
  495. try {
  496. if (requestMode == 2 && !noBackup) {
  497. val backup = backupRepository.findBackupForRestore(
  498. spoofedSimInfoRepo.spoofedSimInfo.value.number
  499. )
  500. if (backup != null) {
  501. AppStateRepo.instance.updateRuntimeFlags(reqState = ReqState.RESTORE)
  502. if (backupRepository.restore(backup)) {
  503. return@withTimeoutOrNull true
  504. } else {
  505. continue
  506. }
  507. }
  508. }
  509. needRest = needRest || appStateRepo.appState.value.requestedNum >= 3
  510. if (needRest && !appPrefsRepo.appPrefs.value.preventReset) {
  511. reset()
  512. needRest = false
  513. }
  514. appStateRepo.incrementRequestedNum()
  515. requestNumberAtomic()
  516. return@withTimeoutOrNull true
  517. } catch (e: Exception) {
  518. if (e is RequestNumberException) {
  519. Log.e(TAG, "requestNumberError: ${e.message}")
  520. } else {
  521. Log.e(TAG, "requestNumberError: ${e.message}", e)
  522. }
  523. }
  524. }
  525. false
  526. }
  527. if (requestSuccess == true) {
  528. spoofedSimInfoRepo.updateSpoofedSimInfo(
  529. spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value.copy(available = true),
  530. suspend = false
  531. )
  532. appStateRepo.resetSuccessNum()
  533. appStateRepo.resetExecutedNum()
  534. Log.i(TAG, "requestNumber success")
  535. } else {
  536. Log.e(TAG, "requestNumber failed")
  537. appStateRepo.updateSend(false)
  538. }
  539. appStateRepo.updateRuntimeFlags(
  540. reqState = ReqState.NONE,
  541. suspended = requestSuccess != true
  542. )
  543. appStateRepo.incrementRequestedNum()
  544. }
  545. private suspend fun checkRcsConnectivity(): Boolean = run checkRcsConnection@{
  546. repeat(3) {
  547. Log.i(TAG, "Checking RCS status...")
  548. shellRun(
  549. CMD_CONVERSATION_LIST_ACTIVITY,
  550. CMD_RCS_SETTINGS_ACTIVITY,
  551. "sleep 1",
  552. )
  553. val res = TraverseResult()
  554. screenInspector.traverseNode(res)
  555. if (res.rcsConnectionStatus == RcsConnectionStatus.CONNECTED) {
  556. Log.i(TAG, "RCS is connected")
  557. shellRun(CMD_BACK)
  558. return@checkRcsConnection true
  559. } else {
  560. Log.i(TAG, "RCS not connected, retrying...")
  561. }
  562. shellRun(CMD_BACK, "sleep ${it * 2}")
  563. }
  564. false
  565. }
  566. suspend fun checkRcsA10y(timeout: Int = 7500, repeatNum: Int = 2): Boolean {
  567. val availability = run checkA10y@{
  568. repeat(repeatNum) {
  569. val rcsConnected = checkRcsConnectivity()
  570. if (rcsConnected) {
  571. val checkRcsA10yNumbers = mutableListOf<String>()
  572. try {
  573. val config = ktorClient
  574. .get(SysConfigApi.Id(SysConfigApi(), "check_availability_numbers"))
  575. .body<SysConfigResponse>()
  576. Log.i(TAG, "sysConfig response: $config")
  577. checkRcsA10yNumbers.addAll(config.value.split(",").map { it.trim() })
  578. } catch (exception: Exception) {
  579. Log.e(TAG, "sysConfig Error: ${exception.message}", exception)
  580. }
  581. if (checkRcsA10yNumbers.isEmpty()) {
  582. Log.e(TAG, "checkRcsA10yNumbers is empty")
  583. return@checkA10y true
  584. }
  585. checkRcsA10yNumbers.forEach {
  586. context.startActivity(smsIntent(it, "", null))
  587. repeat(timeout / 200) {
  588. delay(200)
  589. val traverseResult = TraverseResult()
  590. screenInspector.traverseNode(traverseResult)
  591. if (traverseResult.isRcsCapable) {
  592. return@checkA10y true
  593. } else {
  594. Log.i(TAG, "checkRcsA10y: RCS not detected")
  595. }
  596. }
  597. }
  598. }
  599. shellRun(PACKAGE_MESSAGING.kill(), CMD_MESSAGING_APP, "sleep 5")
  600. }
  601. false
  602. }
  603. if (!availability) {
  604. RcsNumberApi.notifyWasted(spoofedSimInfoRepo.spoofedSimInfo.value.numberId)
  605. }
  606. return availability
  607. }
  608. suspend fun installApk(
  609. installApkAction: InstallApkAction,
  610. onSuccess: () -> Unit,
  611. onError: (Exception) -> Unit
  612. ) {
  613. try {
  614. val file = withContext(Dispatchers.IO) {
  615. File.createTempFile("files", ".apk")
  616. }
  617. HttpClient(OkHttp) {
  618. HttpResponseValidator {
  619. validateResponse { response ->
  620. if (response.status.value !in 200..299) {
  621. throw ServerResponseException(
  622. response,
  623. "Error " + response.status.value.toString()
  624. )
  625. }
  626. }
  627. }
  628. }.prepareGet(installApkAction.data.apkUrl)
  629. .execute { httpResponse ->
  630. val channel: ByteReadChannel = httpResponse.body()
  631. while (!channel.isClosedForRead) {
  632. val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
  633. while (!packet.isEmpty) {
  634. val bytes = packet.readBytes()
  635. file.appendBytes(bytes)
  636. }
  637. }
  638. }
  639. Log.i(TAG, "Apk file saved to ${file.path}")
  640. shellRun("pm install -d -r ${file.path}")
  641. onSuccess()
  642. file.delete()
  643. } catch (e: Exception) {
  644. Log.e(TAG, "Failed to install apk", e)
  645. onError(e)
  646. }
  647. }
  648. suspend fun runScript(
  649. installApkAction: RunScriptAction,
  650. onSuccess: (String, String) -> Unit,
  651. onError: (Exception) -> Unit
  652. ) {
  653. try {
  654. val (out, err) = shellRun(*installApkAction.data.script.split("\n").toTypedArray())
  655. onSuccess(out, err)
  656. } catch (e: Exception) {
  657. Log.e(TAG, "Failed to run script", e)
  658. onError(e)
  659. }
  660. }
  661. suspend fun updateDevice(
  662. updateDeviceAction: UpdateDeviceAction,
  663. onSuccess: () -> Unit,
  664. onError: (Exception) -> Unit
  665. ) {
  666. try {
  667. if (updateDeviceAction.data.id != null) {
  668. appPrefsRepo.updateId(updateDeviceAction.data.id)
  669. }
  670. if (updateDeviceAction.data.name != null) {
  671. appPrefsRepo.updateName(updateDeviceAction.data.name)
  672. }
  673. onSuccess()
  674. } catch (e: Exception) {
  675. Log.e(TAG, "Failed to update device", e)
  676. onError(e)
  677. }
  678. }
  679. suspend fun storeNumbers(n: Int? = null) {
  680. if (storeNumberJob != null) {
  681. Log.e(TAG, "storeNumbers: another store number job is running")
  682. return
  683. }
  684. val num = n ?: appPrefsRepo.appPrefs.value.storeNum
  685. if (num <= 0) {
  686. Log.e(TAG, "storeNumbers: storeNum is 0")
  687. return
  688. }
  689. storeNumberJob = CoroutineScope(coroutineContext).launch {
  690. try {
  691. appStateRepo.updateRuntimeFlags(storing = true)
  692. if (spoofedSimInfoRepo.spoofedSimInfo.value.available && appStateRepo.appState.value.successNum <= 5) {
  693. screenController.toggleRcsSwitch(false)
  694. backupRepository.backup(
  695. type = "auto",
  696. sendCount = appStateRepo.appState.value.successNum,
  697. stock = 1
  698. )
  699. screenController.toggleRcsSwitch(true)
  700. }
  701. var success = true
  702. repeat(num) {
  703. if (!isActive) {
  704. Log.e(TAG, "storeNumbers: job is cancelled, stopping repeat")
  705. return@launch
  706. }
  707. Log.i(TAG, "storeNumbers: $it")
  708. try {
  709. if ((success || appStateRepo.appState.value.requestedNum > 3)
  710. && !(it == 0 && appStateRepo.appState.value.requestedNum == 0)
  711. ) {
  712. reset()
  713. }
  714. requestNumberAtomic(store = true)
  715. spoofedSimInfoRepo.updateSpoofedSimInfo(
  716. spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value.copy(
  717. available = true
  718. ),
  719. suspend = false
  720. )
  721. screenController.toggleRcsSwitch(false)
  722. backupRepository.backup(type = "auto", sendCount = 0, stock = 1)
  723. RcsNumberApi.updateStockFlag(
  724. id = spoofedSimInfoRepo.spoofedSimInfo.value.numberId,
  725. flag = 1
  726. )
  727. success = true
  728. } catch (e: CancellationException) {
  729. Log.e(TAG, "storeNumbers: job is cancelled", e)
  730. } catch (e: Exception) {
  731. success = false
  732. Log.e(TAG, "Error store number", e)
  733. }
  734. appStateRepo.incrementRequestedNum()
  735. }
  736. if (success) {
  737. reset()
  738. }
  739. appStateRepo.updateRuntimeFlags(
  740. reqState = ReqState.NONE,
  741. storing = false
  742. )
  743. storeNumberJob = null
  744. } catch (e: CancellationException) {
  745. Log.e(TAG, "storeNumbers: job is cancelled", e)
  746. }
  747. }
  748. }
  749. suspend fun cancelStoreNumber() {
  750. if (storeNumberJob != null) {
  751. if (storeNumberJob!!.isActive) {
  752. storeNumberJob!!.cancel()
  753. }
  754. appStateRepo.updateRuntimeFlags(
  755. reqState = ReqState.NONE,
  756. storing = false
  757. )
  758. storeNumberJob = null
  759. }
  760. }
  761. suspend fun cleanBackup(start: Long, end: Long) {
  762. backupRepository.cleanBackup(start, end)
  763. }
  764. }