|
|
@@ -6,7 +6,6 @@ import android.annotation.SuppressLint
|
|
|
import android.content.ComponentName
|
|
|
import android.content.Context
|
|
|
import android.content.Intent
|
|
|
-import android.content.pm.ActivityInfo
|
|
|
import android.graphics.PixelFormat
|
|
|
import android.graphics.Rect
|
|
|
import android.net.Uri
|
|
|
@@ -62,6 +61,7 @@ import com.example.modifier.model.SocketCallback
|
|
|
import com.example.modifier.model.TaskAction
|
|
|
import com.example.modifier.model.TaskExecutionResult
|
|
|
import com.example.modifier.model.TelephonyConfig
|
|
|
+import com.example.modifier.serializer.Json
|
|
|
import com.example.modifier.ui.shellRun
|
|
|
import com.google.android.material.color.DynamicColors
|
|
|
import io.ktor.client.call.body
|
|
|
@@ -83,7 +83,6 @@ import kotlinx.coroutines.withContext
|
|
|
import kotlinx.coroutines.withTimeout
|
|
|
import kotlinx.coroutines.withTimeoutOrNull
|
|
|
import kotlinx.serialization.encodeToString
|
|
|
-import kotlinx.serialization.json.Json
|
|
|
import org.apache.commons.collections4.queue.CircularFifoQueue
|
|
|
import org.apache.commons.lang3.RandomStringUtils
|
|
|
import org.json.JSONException
|
|
|
@@ -220,6 +219,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
rcsConfigureState.postValue(RcsConfigureState.CONFIGURED)
|
|
|
} else if (line.contains("destState=WaitingForRcsDefaultOnState")) {
|
|
|
rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_DEFAULT_ON)
|
|
|
+ } else if (line.contains("destState=WaitingForGoogleTosState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_TOS)
|
|
|
} else if (line.contains("destState=RetryState")) {
|
|
|
rcsConfigureState.postValue(RcsConfigureState.RETRY)
|
|
|
}
|
|
|
@@ -252,6 +253,9 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
AppDatabase.getDatabase(this).itemDao()
|
|
|
}
|
|
|
|
|
|
+ private var requestMode = 1;
|
|
|
+ private var currentActivity = ""
|
|
|
+
|
|
|
fun connect() {
|
|
|
try {
|
|
|
load()
|
|
|
@@ -317,17 +321,21 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
|
|
|
override fun onAccessibilityEvent(event: AccessibilityEvent) {
|
|
|
-// traverseNode(getRootInActiveWindow(), new TraverseResult());
|
|
|
-// if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
|
|
-// if (event.packageName != null && event.className != null) {
|
|
|
-// val componentName = ComponentName(
|
|
|
-// event.packageName.toString(),
|
|
|
-// event.className.toString()
|
|
|
-// )
|
|
|
-// Log.i(TAG, "packageName: ${event.packageName}")
|
|
|
-// Log.i(TAG, "className: ${event.className}")
|
|
|
-// }
|
|
|
-// }
|
|
|
+ if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
|
|
+ if (event.packageName != null && event.className != null) {
|
|
|
+ val componentName = ComponentName(
|
|
|
+ event.packageName.toString(),
|
|
|
+ event.className.toString()
|
|
|
+ )
|
|
|
+ try {
|
|
|
+ packageManager.getActivityInfo(componentName, 0)
|
|
|
+ currentActivity = componentName.flattenToShortString()
|
|
|
+ Log.d(TAG, "Activity: $currentActivity")
|
|
|
+ } catch (_: Exception) {
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
override fun onInterrupt() {
|
|
|
@@ -382,6 +390,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
rcsInterval = taskAction.data.config.rcsInterval
|
|
|
requestNumberInterval = taskAction.data.config.requestNumberInterval
|
|
|
currentTaskId = taskAction.data.taskId
|
|
|
+ requestMode = if (taskAction.data.config.useBackup) 2 else 1
|
|
|
|
|
|
if (taskAction.data.config.checkConnection) {
|
|
|
checkingConnection.postValue(true)
|
|
|
@@ -540,6 +549,10 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ val packageInfo = packageManager.getPackageInfo(
|
|
|
+ node.packageName.toString(), 0
|
|
|
+ )
|
|
|
+
|
|
|
val className = node.className.toString()
|
|
|
val name = node.viewIdResourceName
|
|
|
val text = Optional.ofNullable(node.text).map { obj: CharSequence -> obj.toString() }
|
|
|
@@ -560,7 +573,13 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
result.isRcsCapable = true
|
|
|
}
|
|
|
|
|
|
- if (text != null && (text.contains("Turn on RCS chats") || text.contains("开启 RCS 聊天功能"))) {
|
|
|
+ if ("com.google.android.apps.messaging:id/tombstone_message" == id) {
|
|
|
+ result.isRcsCapable = text.contains("聊天") || text.contains("Chatting with")
|
|
|
+ }
|
|
|
+
|
|
|
+ if (text != null && (text.contains("Turn on RCS chats") || text.contains("开启 RCS 聊天功能")
|
|
|
+ || text.contains("Enable chat features") || text.contains("启用聊天功能"))
|
|
|
+ ) {
|
|
|
fun findSwitch(node: AccessibilityNodeInfo): Boolean {
|
|
|
if ("com.google.android.apps.messaging:id/switchWidget" == node.viewIdResourceName) {
|
|
|
result.rcsSwitch = node
|
|
|
@@ -583,6 +602,13 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if ("android:id/title" == id) {
|
|
|
+ when (text) {
|
|
|
+ "状态:已连接" -> result.rcsConnectionStatus = RcsConnectionStatus.CONNECTED
|
|
|
+ "Status: Connected" -> result.rcsConnectionStatus = RcsConnectionStatus.CONNECTED
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (node.childCount != 0) {
|
|
|
for (i in 0 until node.childCount) {
|
|
|
traverseNode(node.getChild(i), result)
|
|
|
@@ -704,7 +730,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
|
|
|
binding.btnReq.setOnClickListener {
|
|
|
CoroutineScope(Dispatchers.IO).launch {
|
|
|
- requestNumber(true)
|
|
|
+ requestNumber(reset = false, noBackup = true)
|
|
|
}
|
|
|
}
|
|
|
binding.btnInspect.setOnClickListener {
|
|
|
@@ -768,7 +794,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private suspend fun waitForRcsState(
|
|
|
+ suspend fun waitForRcsState(
|
|
|
states: Array<RcsConfigureState>,
|
|
|
timeout: Duration
|
|
|
): RcsConfigureState? {
|
|
|
@@ -800,12 +826,10 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
|
|
|
suspend fun toggleRcsSwitch(on: Boolean, retry: Int = 3): Boolean {
|
|
|
-
|
|
|
val res = TraverseResult()
|
|
|
|
|
|
shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 0.5")
|
|
|
val success = run repeatBlock@{
|
|
|
-
|
|
|
repeat(retry) {
|
|
|
res.rcsSwitch = null
|
|
|
traverseNode(rootInActiveWindow, res)
|
|
|
@@ -820,19 +844,29 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
if (on) {
|
|
|
shellRun(
|
|
|
"input tap ${rect.centerX()} ${rect.centerY()}", "sleep 1",
|
|
|
- CMD_BACK, "sleep 0.5",
|
|
|
- CMD_RCS_SETTINGS_ACTIVITY, "sleep 1",
|
|
|
)
|
|
|
+ if (isOldVersion()) {
|
|
|
+ rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
|
|
|
+ .firstOrNull()?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
|
|
+ delay(1000)
|
|
|
+ }
|
|
|
+ while ("com.google.android.apps.messaging/.ui.appsettings.RcsSettingsActivity" == currentActivity) {
|
|
|
+ shellRun(CMD_BACK)
|
|
|
+ delay(500)
|
|
|
+ }
|
|
|
+ shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
|
|
|
} else {
|
|
|
shellRun(
|
|
|
"input tap ${rect.centerX()} ${rect.centerY()}", "sleep 1",
|
|
|
)
|
|
|
rootInActiveWindow.findAccessibilityNodeInfosByViewId("android:id/button1")
|
|
|
.firstOrNull()?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
|
|
- shellRun(
|
|
|
- "sleep 0.5", CMD_BACK, "sleep 0.5",
|
|
|
- CMD_RCS_SETTINGS_ACTIVITY, "sleep 0.5",
|
|
|
- )
|
|
|
+ delay(1000)
|
|
|
+ while ("com.google.android.apps.messaging/.ui.appsettings.RcsSettingsActivity" == currentActivity) {
|
|
|
+ shellRun(CMD_BACK)
|
|
|
+ delay(500)
|
|
|
+ }
|
|
|
+ shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
|
|
|
}
|
|
|
res.rcsSwitch = null
|
|
|
traverseNode(rootInActiveWindow, res)
|
|
|
@@ -843,73 +877,152 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
false
|
|
|
}
|
|
|
- shellRun(CMD_BACK, "sleep 0.5")
|
|
|
+ while ("com.google.android.apps.messaging/.ui.appsettings.RcsSettingsActivity" == currentActivity) {
|
|
|
+ shellRun(CMD_BACK)
|
|
|
+ delay(500)
|
|
|
+ }
|
|
|
return success
|
|
|
}
|
|
|
|
|
|
+ private fun isOldVersion(): Boolean {
|
|
|
+ val info = packageManager.getPackageInfo("com.google.android.apps.messaging", 0)
|
|
|
+ var oldVersion = false
|
|
|
+ if (info != null) {
|
|
|
+ if (info.versionCode < 170545910) {
|
|
|
+ oldVersion = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return oldVersion
|
|
|
+ }
|
|
|
+
|
|
|
private suspend fun reset() {
|
|
|
- withTimeout(1.hours) {
|
|
|
- while (true) {
|
|
|
- delay(100)
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Waiting for RCS switch on..."
|
|
|
- }
|
|
|
- rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
- Global.saveMock()
|
|
|
- resetAll()
|
|
|
- var switchAppear = waitForRcsState(
|
|
|
- arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
|
|
|
- 1.minutes
|
|
|
- )?.let {
|
|
|
- it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
|
|
|
+ if (isOldVersion()) {
|
|
|
+ withTimeout(1.hours) {
|
|
|
+ while (true) {
|
|
|
+ delay(100)
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Waiting for RCS switch on..."
|
|
|
+ }
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+ Global.saveMock()
|
|
|
+ resetAll()
|
|
|
+ var switchAppear = waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_TOS),
|
|
|
+ 1.minutes
|
|
|
+ )?.let {
|
|
|
+ it == RcsConfigureState.WAITING_FOR_TOS
|
|
|
+ }
|
|
|
+ if (switchAppear != true) {
|
|
|
+ shellRun(
|
|
|
+ CMD_KILL_GMS, CMD_KILL_MESSAGING_APP, "sleep 1",
|
|
|
+ CMD_MESSAGING_APP
|
|
|
+ )
|
|
|
+ switchAppear = waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_TOS),
|
|
|
+ 2.minutes
|
|
|
+ )?.let {
|
|
|
+ it == RcsConfigureState.WAITING_FOR_TOS
|
|
|
+ }
|
|
|
+ if (switchAppear != true) {
|
|
|
+ Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!toggleRcsSwitch(false)) {
|
|
|
+ Log.e(TAG, "RCS switch not turned off, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if (!toggleRcsSwitch(true)) {
|
|
|
+ Log.e(TAG, "RCS switch not turned on, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ var resetSuccess = waitForRcsState(
|
|
|
+ arrayOf(
|
|
|
+ RcsConfigureState.READY
|
|
|
+ ), 30.seconds
|
|
|
+ ).let { it == RcsConfigureState.READY }
|
|
|
+ if (!resetSuccess) {
|
|
|
+ toggleRcsSwitch(false)
|
|
|
+ delay(1000)
|
|
|
+ toggleRcsSwitch(true)
|
|
|
+ resetSuccess = waitForRcsState(
|
|
|
+ arrayOf(
|
|
|
+ RcsConfigureState.READY
|
|
|
+ ), 1.minutes
|
|
|
+ ).let { it == RcsConfigureState.READY }
|
|
|
+ }
|
|
|
+ Log.i(TAG, "waitForRcsState: $resetSuccess")
|
|
|
+ requestNumberCount = 0
|
|
|
+ if (resetSuccess) {
|
|
|
+ delay(3000)
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
- if (switchAppear != true) {
|
|
|
- shellRun(
|
|
|
- CMD_KILL_GMS, CMD_KILL_MESSAGING_APP, "sleep 1",
|
|
|
- CMD_MESSAGING_APP
|
|
|
- )
|
|
|
- switchAppear = waitForRcsState(
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ withTimeout(1.hours) {
|
|
|
+ while (true) {
|
|
|
+ delay(100)
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Waiting for RCS switch on..."
|
|
|
+ }
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+ Global.saveMock()
|
|
|
+ resetAll()
|
|
|
+ var switchAppear = waitForRcsState(
|
|
|
arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
|
|
|
- 2.minutes
|
|
|
+ 1.minutes
|
|
|
)?.let {
|
|
|
it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
|
|
|
}
|
|
|
if (switchAppear != true) {
|
|
|
- Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
+ shellRun(
|
|
|
+ CMD_KILL_GMS, CMD_KILL_MESSAGING_APP, "sleep 1",
|
|
|
+ CMD_MESSAGING_APP
|
|
|
+ )
|
|
|
+ switchAppear = waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
|
|
|
+ 2.minutes
|
|
|
+ )?.let {
|
|
|
+ it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
|
|
|
+ }
|
|
|
+ if (switchAppear != true) {
|
|
|
+ Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ val switchOn = toggleRcsSwitch(true)
|
|
|
+ if (!switchOn) {
|
|
|
+ Log.e(TAG, "RCS switch not turned on, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
- }
|
|
|
- val switchOn = toggleRcsSwitch(true)
|
|
|
- if (!switchOn) {
|
|
|
- Log.e(TAG, "RCS switch not turned on, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
- var resetSuccess = waitForRcsState(
|
|
|
- arrayOf(
|
|
|
- RcsConfigureState.READY
|
|
|
- ), 30.seconds
|
|
|
- ).let { it == RcsConfigureState.READY }
|
|
|
- if (!resetSuccess) {
|
|
|
- toggleRcsSwitch(false)
|
|
|
- delay(1000)
|
|
|
- toggleRcsSwitch(true)
|
|
|
- resetSuccess = waitForRcsState(
|
|
|
+ var resetSuccess = waitForRcsState(
|
|
|
arrayOf(
|
|
|
RcsConfigureState.READY
|
|
|
- ), 1.minutes
|
|
|
+ ), 30.seconds
|
|
|
).let { it == RcsConfigureState.READY }
|
|
|
- }
|
|
|
- Log.i(TAG, "waitForRcsState: $resetSuccess")
|
|
|
- requestNumberCount = 0
|
|
|
- if (resetSuccess) {
|
|
|
- delay(3000)
|
|
|
- break
|
|
|
+ if (!resetSuccess) {
|
|
|
+ toggleRcsSwitch(false)
|
|
|
+ delay(1000)
|
|
|
+ toggleRcsSwitch(true)
|
|
|
+ resetSuccess = waitForRcsState(
|
|
|
+ arrayOf(
|
|
|
+ RcsConfigureState.READY
|
|
|
+ ), 1.minutes
|
|
|
+ ).let { it == RcsConfigureState.READY }
|
|
|
+ }
|
|
|
+ Log.i(TAG, "waitForRcsState: $resetSuccess")
|
|
|
+ requestNumberCount = 0
|
|
|
+ if (resetSuccess) {
|
|
|
+ delay(3000)
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private suspend fun requestNumber(reset: Boolean = false) {
|
|
|
+ private suspend fun requestNumber(reset: Boolean = false, noBackup: Boolean = false) {
|
|
|
val color = ContextCompat.getColorStateList(binding.root.context, R.color.btn_color)
|
|
|
binding.btnReq.backgroundTintList = color
|
|
|
if (getSharedPreferences("settings", Context.MODE_PRIVATE)
|
|
|
@@ -926,170 +1039,189 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
backup(backupItemDao, "auto", sendCount)
|
|
|
|
|
|
var requestSuccess = false
|
|
|
- withTimeoutOrNull(1.hours) {
|
|
|
- var needRest = reset
|
|
|
- while (true) {
|
|
|
- delay(200)
|
|
|
- try {
|
|
|
- if (needRest &&
|
|
|
- !getSharedPreferences("settings", Context.MODE_PRIVATE)
|
|
|
- .getBoolean("do_not_reset", false)
|
|
|
- ) {
|
|
|
- reset()
|
|
|
- needRest = false
|
|
|
- }
|
|
|
+ if (requestMode == 2 && !noBackup) {
|
|
|
+ val backup = backupItemDao.findBackupForRestore(
|
|
|
+ Global.telephonyConfig.number,
|
|
|
+ System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000
|
|
|
+ )
|
|
|
+ if (backup != null) {
|
|
|
+ Global.restore(backup)
|
|
|
+ requestSuccess = true
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Requesting number..."
|
|
|
- }
|
|
|
+ if (!requestSuccess) {
|
|
|
+ withTimeoutOrNull(1.hours) {
|
|
|
+ var needRest = reset
|
|
|
+ while (true) {
|
|
|
+ delay(200)
|
|
|
+ try {
|
|
|
+ if (needRest &&
|
|
|
+ !getSharedPreferences("settings", Context.MODE_PRIVATE)
|
|
|
+ .getBoolean("do_not_reset", false)
|
|
|
+ ) {
|
|
|
+ reset()
|
|
|
+ needRest = false
|
|
|
+ }
|
|
|
+
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Requesting number..."
|
|
|
+ }
|
|
|
|
|
|
- val response = KtorClient.put(
|
|
|
- RcsNumberApi()
|
|
|
- ) {
|
|
|
- contentType(ContentType.Application.Json)
|
|
|
- setBody(
|
|
|
- RcsNumberRequest(
|
|
|
- deviceId = Utils.getUniqueID(),
|
|
|
- taskId = currentTaskId
|
|
|
+ val response = KtorClient.put(
|
|
|
+ RcsNumberApi()
|
|
|
+ ) {
|
|
|
+ contentType(ContentType.Application.Json)
|
|
|
+ setBody(
|
|
|
+ RcsNumberRequest(
|
|
|
+ deviceId = Utils.getUniqueID(),
|
|
|
+ taskId = currentTaskId
|
|
|
+ )
|
|
|
)
|
|
|
- )
|
|
|
- }
|
|
|
- var rcsNumber = response.body<RcsNumberResponse>()
|
|
|
- Log.i(TAG, "requestNumber response: $rcsNumber")
|
|
|
+ }
|
|
|
+ var rcsNumber = response.body<RcsNumberResponse>()
|
|
|
+ Log.i(TAG, "requestNumber response: $rcsNumber")
|
|
|
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Requesting success, waiting for logs..."
|
|
|
- }
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Requesting success, waiting for logs..."
|
|
|
+ }
|
|
|
|
|
|
- Global.save(
|
|
|
- TelephonyConfig(
|
|
|
- rcsNumber.number,
|
|
|
- rcsNumber.mcc,
|
|
|
- rcsNumber.mnc,
|
|
|
- Global.genICCID(rcsNumber.mnc, rcsNumber.areaCode),
|
|
|
- rcsNumber.mcc + rcsNumber.mnc + RandomStringUtils.randomNumeric(
|
|
|
- 15 - rcsNumber.mcc.length - rcsNumber.mnc.length
|
|
|
- ),
|
|
|
- Utils.generateIMEI(),
|
|
|
- rcsNumber.country,
|
|
|
- rcsNumber.areaCode
|
|
|
+ Global.save(
|
|
|
+ TelephonyConfig(
|
|
|
+ rcsNumber.number,
|
|
|
+ rcsNumber.mcc,
|
|
|
+ rcsNumber.mnc,
|
|
|
+ Global.genICCID(rcsNumber.mnc, rcsNumber.areaCode),
|
|
|
+ rcsNumber.mcc + rcsNumber.mnc + RandomStringUtils.randomNumeric(
|
|
|
+ 15 - rcsNumber.mcc.length - rcsNumber.mnc.length
|
|
|
+ ),
|
|
|
+ Utils.generateIMEI(),
|
|
|
+ rcsNumber.country,
|
|
|
+ rcsNumber.areaCode
|
|
|
+ )
|
|
|
)
|
|
|
- )
|
|
|
|
|
|
- shellRun(CMD_MESSAGING_APP)
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Waiting for logs..."
|
|
|
- }
|
|
|
+ shellRun(CMD_MESSAGING_APP)
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Waiting for logs..."
|
|
|
+ }
|
|
|
|
|
|
- if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
|
|
|
- Log.e(TAG, "RCS number expired, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
- var sendOtpTimeout = ChronoUnit.SECONDS.between(
|
|
|
- LocalDateTime.now(),
|
|
|
- rcsNumber.expiryTime
|
|
|
- ).seconds
|
|
|
- if (sendOtpTimeout < 60.seconds) {
|
|
|
- Log.e(TAG, "OTP timeout too short, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
- if (sendOtpTimeout > 2.minutes) {
|
|
|
- sendOtpTimeout = 2.minutes
|
|
|
- }
|
|
|
- if (waitForRcsState(
|
|
|
- arrayOf(RcsConfigureState.WAITING_FOR_OTP),
|
|
|
- sendOtpTimeout
|
|
|
- ) != RcsConfigureState.WAITING_FOR_OTP
|
|
|
- ) {
|
|
|
- if (!toggleRcsSwitch(true)) {
|
|
|
- needRest = true
|
|
|
+ if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
|
|
|
+ Log.e(TAG, "RCS number expired, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ var sendOtpTimeout = ChronoUnit.SECONDS.between(
|
|
|
+ LocalDateTime.now(),
|
|
|
+ rcsNumber.expiryTime
|
|
|
+ ).seconds
|
|
|
+ if (sendOtpTimeout < 60.seconds) {
|
|
|
+ Log.e(TAG, "OTP timeout too short, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if (sendOtpTimeout > 2.minutes) {
|
|
|
+ sendOtpTimeout = 2.minutes
|
|
|
+ }
|
|
|
+ if (waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_OTP),
|
|
|
+ sendOtpTimeout
|
|
|
+ ) != RcsConfigureState.WAITING_FOR_OTP
|
|
|
+ ) {
|
|
|
+ if (!toggleRcsSwitch(true)) {
|
|
|
+ needRest = true
|
|
|
+ }
|
|
|
+ Log.e(TAG, "RCS not entered waiting for OTP state, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
|
|
|
+ Log.e(TAG, "RCS number expired, retrying...")
|
|
|
+ continue
|
|
|
}
|
|
|
- Log.e(TAG, "RCS not entered waiting for OTP state, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
- if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
|
|
|
- Log.e(TAG, "RCS number expired, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
|
|
|
- withTimeoutOrNull(60.seconds) {
|
|
|
- while (true) {
|
|
|
- try {
|
|
|
- rcsNumber = KtorClient.get(RcsNumberApi.Id(id = rcsNumber.id))
|
|
|
- .body<RcsNumberResponse>()
|
|
|
- Log.i(TAG, "wait for otp response: $rcsNumber")
|
|
|
- if (rcsNumber.status == RcsNumberResponse.STATUS_SUCCESS || rcsNumber.status == RcsNumberResponse.STATUS_EXPIRED) {
|
|
|
- break
|
|
|
+ withTimeoutOrNull(60.seconds) {
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+ rcsNumber = KtorClient.get(RcsNumberApi.Id(id = rcsNumber.id))
|
|
|
+ .body<RcsNumberResponse>()
|
|
|
+ Log.i(TAG, "wait for otp response: $rcsNumber")
|
|
|
+ if (rcsNumber.status == RcsNumberResponse.STATUS_SUCCESS || rcsNumber.status == RcsNumberResponse.STATUS_EXPIRED) {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } catch (exception: Exception) {
|
|
|
+ Log.e(TAG, "wait for otp Error: ${exception.stackTrace}")
|
|
|
}
|
|
|
- } catch (exception: Exception) {
|
|
|
- Log.e(TAG, "wait for otp Error: ${exception.stackTrace}")
|
|
|
+ delay(2.seconds)
|
|
|
}
|
|
|
- delay(2.seconds)
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (rcsNumber.status != RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
- Log.e(TAG, "OTP not received, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- val match =
|
|
|
- Regex("Your Messenger verification code is G-(\\d{6})")
|
|
|
- .matchEntire(rcsNumber.message!!)
|
|
|
- if (match != null) {
|
|
|
- val otp = match.groupValues[1]
|
|
|
- Log.i(TAG, "OTP: $otp")
|
|
|
- val sender = "3538"
|
|
|
- val msg = "Your Messenger verification code is G-$otp"
|
|
|
-
|
|
|
- val configured = run configuring@{
|
|
|
- repeat(2) {
|
|
|
- Global.sendSmsIntent(sender, msg)
|
|
|
- val state =
|
|
|
- waitForRcsState(
|
|
|
- arrayOf(
|
|
|
- RcsConfigureState.CONFIGURED,
|
|
|
- RcsConfigureState.RETRY
|
|
|
- ), 60.seconds
|
|
|
- )
|
|
|
- when (state) {
|
|
|
- RcsConfigureState.CONFIGURED -> {
|
|
|
- return@configuring true
|
|
|
- }
|
|
|
+ if (rcsNumber.status != RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
+ Log.e(TAG, "OTP not received, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
|
|
|
- RcsConfigureState.RETRY -> {
|
|
|
+ val match =
|
|
|
+ Regex("Your Messenger verification code is G-(\\d{6})")
|
|
|
+ .matchEntire(rcsNumber.message!!)
|
|
|
+ if (match != null) {
|
|
|
+ val otp = match.groupValues[1]
|
|
|
+ Log.i(TAG, "OTP: $otp")
|
|
|
+ val sender = "3538"
|
|
|
+ val msg = "Your Messenger verification code is G-$otp"
|
|
|
+
|
|
|
+ val configured = run configuring@{
|
|
|
+ repeat(2) {
|
|
|
+ Global.sendSmsIntent(sender, msg)
|
|
|
+ val state =
|
|
|
waitForRcsState(
|
|
|
- arrayOf(RcsConfigureState.WAITING_FOR_OTP),
|
|
|
- 60.seconds
|
|
|
+ arrayOf(
|
|
|
+ RcsConfigureState.CONFIGURED,
|
|
|
+ RcsConfigureState.RETRY
|
|
|
+ ), 60.seconds
|
|
|
)
|
|
|
- }
|
|
|
-
|
|
|
- else -> {
|
|
|
- Log.e(TAG, "verifyOtp fail, retrying...")
|
|
|
+ when (state) {
|
|
|
+ RcsConfigureState.CONFIGURED -> {
|
|
|
+ return@configuring true
|
|
|
+ }
|
|
|
+
|
|
|
+ RcsConfigureState.RETRY -> {
|
|
|
+ waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_OTP),
|
|
|
+ 60.seconds
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ else -> {
|
|
|
+ Log.e(TAG, "verifyOtp fail, retrying...")
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ false
|
|
|
+ }
|
|
|
+ if (!configured) {
|
|
|
+ Log.e(TAG, "RCS not configured, retrying...")
|
|
|
+ continue
|
|
|
+ } else {
|
|
|
+ requestSuccess = true
|
|
|
+ break
|
|
|
}
|
|
|
- false
|
|
|
- }
|
|
|
- if (!configured) {
|
|
|
- Log.e(TAG, "RCS not configured, retrying...")
|
|
|
- continue
|
|
|
- } else {
|
|
|
- requestSuccess = true
|
|
|
- break
|
|
|
}
|
|
|
+ } catch (e: Exception) {
|
|
|
+ Log.e(TAG, "requestNumberError: ${e.message}", e)
|
|
|
}
|
|
|
- } catch (e: Exception) {
|
|
|
- Log.e(TAG, "requestNumberError: ${e.message}", e)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
requesting.postValue(false)
|
|
|
+
|
|
|
if (requestSuccess) {
|
|
|
sendCount = 0
|
|
|
counter = 0
|
|
|
Log.i(TAG, "requestNumber success")
|
|
|
+ if (isOldVersion()) {
|
|
|
+ delay(5000)
|
|
|
+ shellRun(CMD_KILL_MESSAGING_APP, "sleep 1", CMD_MESSAGING_APP)
|
|
|
+ delay(2000)
|
|
|
+ }
|
|
|
} else {
|
|
|
Log.e(TAG, "requestNumber failed")
|
|
|
canSend = false
|