TaskRunner.kt 31 KB

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