|
|
@@ -56,10 +56,12 @@ import io.socket.emitter.Emitter
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
import kotlinx.coroutines.delay
|
|
|
+import kotlinx.coroutines.isActive
|
|
|
import kotlinx.coroutines.launch
|
|
|
import kotlinx.coroutines.runBlocking
|
|
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
|
import kotlinx.coroutines.withContext
|
|
|
+import kotlinx.coroutines.withTimeout
|
|
|
import kotlinx.coroutines.withTimeoutOrNull
|
|
|
import org.apache.commons.collections4.queue.CircularFifoQueue
|
|
|
import org.apache.commons.lang3.RandomStringUtils
|
|
|
@@ -72,10 +74,13 @@ import java.util.concurrent.ScheduledExecutorService
|
|
|
import java.util.concurrent.ScheduledThreadPoolExecutor
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
import java.util.concurrent.atomic.AtomicReference
|
|
|
+import kotlin.coroutines.coroutineContext
|
|
|
import kotlin.coroutines.resume
|
|
|
import kotlin.math.max
|
|
|
import kotlin.math.min
|
|
|
+import kotlin.time.Duration
|
|
|
import kotlin.time.Duration.Companion.hours
|
|
|
+import kotlin.time.Duration.Companion.minutes
|
|
|
import kotlin.time.Duration.Companion.seconds
|
|
|
|
|
|
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "serverConfig")
|
|
|
@@ -170,10 +175,11 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
p.inputStream
|
|
|
.bufferedReader()
|
|
|
.useLines { lines ->
|
|
|
- Log.d(TAG, "logcat new lines")
|
|
|
lines.forEach { line ->
|
|
|
if (line.contains("destState=CheckPreconditionsState")) {
|
|
|
rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+ } else if (line.contains("destState=ReadyState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.READY)
|
|
|
} else if (line.contains("destState=WaitingForOtpState")) {
|
|
|
rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_OTP)
|
|
|
} else if (line.contains("destState=VerifyOtpState")) {
|
|
|
@@ -182,8 +188,10 @@ 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=RetryState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.RETRY)
|
|
|
}
|
|
|
- Regex("(?<time>\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3}) I/BugleRcsEngine\\(\\W*\\d+\\)(?<log>.*)").matchEntire(
|
|
|
+ Regex("(?<time>\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3}) I/BugleRcsEngine\\(\\W*\\d+\\): (?<log>.*)").matchEntire(
|
|
|
line
|
|
|
)?.apply {
|
|
|
val time = groups["time"]?.value?.dropLast(4)
|
|
|
@@ -196,6 +204,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
if (log.contains("destState=")) {
|
|
|
logs.add("$time: $log")
|
|
|
emit(logs.joinToString("\n"))
|
|
|
+ delay(100)
|
|
|
+ emit(logs.joinToString("\n"))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -496,7 +506,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
val downParamX = AtomicReference(0)
|
|
|
val downParamY = AtomicReference(0)
|
|
|
|
|
|
- var touchListener = OnTouchListener { v, event ->
|
|
|
+ val touchListener = OnTouchListener { v, event ->
|
|
|
when (event.action) {
|
|
|
MotionEvent.ACTION_DOWN -> {
|
|
|
downX.set(event.rawX)
|
|
|
@@ -584,143 +594,186 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private suspend fun waitForRcsState(
|
|
|
+ states: Array<RcsConfigureState>,
|
|
|
+ timeout: Duration
|
|
|
+ ): RcsConfigureState? {
|
|
|
+ var state: RcsConfigureState? = null
|
|
|
+ withTimeoutOrNull(timeout) {
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ suspendCancellableCoroutine { continuation ->
|
|
|
+ val observer = Observer<RcsConfigureState> { value ->
|
|
|
+ if (states.contains(value)) {
|
|
|
+ state = value
|
|
|
+ if (isActive)
|
|
|
+ continuation.resume(Unit)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rcsConfigureState.observeForever(observer)
|
|
|
+
|
|
|
+ continuation.invokeOnCancellation {
|
|
|
+ Log.i(TAG, "removeObserver")
|
|
|
+ rcsConfigureState.removeObserver(observer)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ false
|
|
|
+ }
|
|
|
+ return state
|
|
|
+ }
|
|
|
+
|
|
|
private suspend fun requestNumber() {
|
|
|
+ requestNumberCount++
|
|
|
requesting.postValue(true)
|
|
|
val result = withTimeoutOrNull(1.hours) {
|
|
|
while (true) {
|
|
|
withContext(Dispatchers.Main) {
|
|
|
binding.tvLog.text = "Waiting for logs..."
|
|
|
}
|
|
|
- requestNumberCount++
|
|
|
- if (requestNumberCount > 5) {
|
|
|
- requestNumberCount = 0
|
|
|
|
|
|
+ var rcsRes: RcsNumberResponse? = null
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+
|
|
|
+ withTimeout(120.seconds) {
|
|
|
while (true) {
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Waiting for logs..."
|
|
|
- }
|
|
|
- rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
- resetAll()
|
|
|
- val switchAppear = withTimeoutOrNull(60.seconds) {
|
|
|
- while (true) {
|
|
|
- if (rcsConfigureState.value == RcsConfigureState.WAITING_FOR_DEFAULT_ON) {
|
|
|
- break
|
|
|
- }
|
|
|
- delay(1.seconds)
|
|
|
+ try {
|
|
|
+ val response = KtorClient.put(
|
|
|
+ RcsNumberApi()
|
|
|
+ ) {
|
|
|
+ contentType(ContentType.Application.Json)
|
|
|
+ setBody(
|
|
|
+ RcsNumberRequest(
|
|
|
+ deviceId = Utils.getUniqueID(),
|
|
|
+ taskId = currentTaskId
|
|
|
+ )
|
|
|
+ )
|
|
|
}
|
|
|
- true
|
|
|
- } ?: false
|
|
|
- if (!switchAppear) {
|
|
|
- Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
- Utils.runAsRoot(
|
|
|
- "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.RcsSettingsActivity",
|
|
|
- "sleep 1"
|
|
|
- )
|
|
|
- val res = TraverseResult()
|
|
|
- traverseNode(rootInActiveWindow, res)
|
|
|
- if (res.rcsSwitch == null) {
|
|
|
- Log.e(TAG, "RCS switch not found, retrying...")
|
|
|
- continue
|
|
|
+ rcsRes = response.body<RcsNumberResponse>()
|
|
|
+ Log.i(TAG, "requestNumber response: $rcsRes")
|
|
|
+ break
|
|
|
+ } catch (exception: Exception) {
|
|
|
+ exception.printStackTrace()
|
|
|
+ delay(2000)
|
|
|
}
|
|
|
- val rect = Rect()
|
|
|
- res.rcsSwitch.getBoundsInScreen(rect)
|
|
|
- Utils.runAsRoot(
|
|
|
- "input tap ${rect.centerX()} ${rect.centerY()}",
|
|
|
- "sleep 1",
|
|
|
- "input keyevent KEYCODE_BACK",
|
|
|
- "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.RcsSettingsActivity",
|
|
|
- )
|
|
|
- Log.i(TAG, "RCS switch turned on, waiting 60 seconds...")
|
|
|
- delay(60000)
|
|
|
- break
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
- lateinit var rcsRes: RcsNumberResponse
|
|
|
- rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
- try {
|
|
|
- val response = KtorClient.put(
|
|
|
- RcsNumberApi()
|
|
|
- ) {
|
|
|
- contentType(ContentType.Application.Json)
|
|
|
- setBody(
|
|
|
- RcsNumberRequest(
|
|
|
- deviceId = Utils.getUniqueID(),
|
|
|
- taskId = currentTaskId
|
|
|
- )
|
|
|
- )
|
|
|
- }
|
|
|
- rcsRes = response.body<RcsNumberResponse>()
|
|
|
- Log.i(TAG, "requestNumber response: $rcsRes")
|
|
|
- } catch (exception: Exception) {
|
|
|
- exception.printStackTrace()
|
|
|
- delay(2000)
|
|
|
+ if (rcsRes == null) {
|
|
|
+ Log.e(TAG, "requestNumber fail, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
Global.save(
|
|
|
TelephonyConfig(
|
|
|
- rcsRes.number,
|
|
|
- rcsRes.mcc,
|
|
|
- rcsRes.mnc,
|
|
|
+ rcsRes!!.number,
|
|
|
+ rcsRes!!.mcc,
|
|
|
+ rcsRes!!.mnc,
|
|
|
RandomStringUtils.randomNumeric(20),
|
|
|
- rcsRes.mcc + rcsRes.mnc + RandomStringUtils.randomNumeric(
|
|
|
- 15 - rcsRes.mcc.length - rcsRes.mnc.length
|
|
|
+ rcsRes!!.mcc + rcsRes!!.mnc + RandomStringUtils.randomNumeric(
|
|
|
+ 15 - rcsRes!!.mcc.length - rcsRes!!.mnc.length
|
|
|
),
|
|
|
Utils.generateIMEI(),
|
|
|
- rcsRes.country
|
|
|
+ rcsRes!!.country
|
|
|
)
|
|
|
)
|
|
|
- delay(1000)
|
|
|
- Utils.runAsRoot("am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER com.google.android.apps.messaging")
|
|
|
- delay(1000)
|
|
|
- Utils.runAsRoot(
|
|
|
- "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.SettingsActivity",
|
|
|
- "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.RcsSettingsActivity"
|
|
|
- )
|
|
|
- delay(1000)
|
|
|
|
|
|
- val waitingForOtp = withTimeoutOrNull(30000) {
|
|
|
- repeat(1000) {
|
|
|
- if (rcsConfigureState.value == RcsConfigureState.WAITING_FOR_OTP) {
|
|
|
- return@repeat
|
|
|
+ var otpTimeout = 60.seconds
|
|
|
+ if (requestNumberCount > 5) {
|
|
|
+ otpTimeout = 60.seconds
|
|
|
+ val resetSuccess = withTimeoutOrNull(5.minutes) {
|
|
|
+ while (true) {
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Waiting for logs..."
|
|
|
+ }
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+ resetAll()
|
|
|
+ val switchAppear = withTimeoutOrNull(60.seconds) {
|
|
|
+ while (true) {
|
|
|
+ if (rcsConfigureState.value == RcsConfigureState.WAITING_FOR_DEFAULT_ON) {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ delay(1.seconds)
|
|
|
+ }
|
|
|
+ true
|
|
|
+ } ?: false
|
|
|
+ if (!switchAppear) {
|
|
|
+ Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ Utils.runAsRoot(
|
|
|
+ "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.RcsSettingsActivity",
|
|
|
+ "sleep 1"
|
|
|
+ )
|
|
|
+ val res = TraverseResult()
|
|
|
+ traverseNode(rootInActiveWindow, res)
|
|
|
+ if (res.rcsSwitch == null) {
|
|
|
+ Log.e(TAG, "RCS switch not found, retrying...")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ val rect = Rect()
|
|
|
+ res.rcsSwitch.getBoundsInScreen(rect)
|
|
|
+ Utils.runAsRoot(
|
|
|
+ "input tap ${rect.centerX()} ${rect.centerY()}",
|
|
|
+ "sleep 1",
|
|
|
+ "input keyevent KEYCODE_BACK",
|
|
|
+ "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.RcsSettingsActivity",
|
|
|
+ )
|
|
|
+ Log.i(TAG, "RCS switch turned on, waiting for state change...")
|
|
|
+
|
|
|
+ val resetSuccess = waitForRcsState(
|
|
|
+ arrayOf(
|
|
|
+ RcsConfigureState.READY,
|
|
|
+ RcsConfigureState.RETRY
|
|
|
+ ), 60.seconds
|
|
|
+ )
|
|
|
+ Log.i(TAG, "waitForRcsState: $resetSuccess")
|
|
|
+
|
|
|
+ requestNumberCount = 0
|
|
|
+ break
|
|
|
}
|
|
|
- delay(1000)
|
|
|
+ true
|
|
|
+ } ?: false
|
|
|
+ if (!resetSuccess) {
|
|
|
+ Log.e(TAG, "RCS reset failed, retrying...")
|
|
|
+ continue
|
|
|
}
|
|
|
- true
|
|
|
- } ?: false
|
|
|
+ } else {
|
|
|
+ Global.revealMessaging()
|
|
|
+ }
|
|
|
|
|
|
- if (!waitingForOtp) {
|
|
|
+ if (waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_OTP),
|
|
|
+ otpTimeout
|
|
|
+ ) != RcsConfigureState.WAITING_FOR_OTP
|
|
|
+ ) {
|
|
|
Log.e(TAG, "RCS not entered waiting for OTP state, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- withTimeoutOrNull(30000) {
|
|
|
+ withTimeoutOrNull(60.seconds) {
|
|
|
while (true) {
|
|
|
try {
|
|
|
- rcsRes = KtorClient.get(RcsNumberApi.Id(id = rcsRes.id))
|
|
|
+ rcsRes = KtorClient.get(RcsNumberApi.Id(id = rcsRes!!.id))
|
|
|
.body<RcsNumberResponse>()
|
|
|
Log.i(TAG, "wait for otp response: $rcsRes")
|
|
|
- if (rcsRes.status == RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
+ if (rcsRes!!.status == RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
break
|
|
|
}
|
|
|
} catch (exception: Exception) {
|
|
|
Log.e(TAG, "wait for otp Error: ${exception.stackTrace}")
|
|
|
}
|
|
|
- delay(2000)
|
|
|
+ delay(2.seconds)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (rcsRes.status != RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
+ if (rcsRes!!.status != RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
Log.e(TAG, "OTP not received, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
val match =
|
|
|
Regex("Your Messenger verification code is G-(\\d{6})")
|
|
|
- .matchEntire(rcsRes.message!!)
|
|
|
+ .matchEntire(rcsRes!!.message!!)
|
|
|
if (match != null) {
|
|
|
val otp = match.groupValues[1]
|
|
|
Log.i(TAG, "OTP: $otp")
|
|
|
@@ -732,53 +785,23 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
"Your Messenger verification code is G-$otp"
|
|
|
)
|
|
|
|
|
|
- suspend fun waitForConfigured(): Boolean {
|
|
|
- sendBroadcast(intent)
|
|
|
- val configured = withTimeoutOrNull(30.seconds) {
|
|
|
- while (true) {
|
|
|
- if (rcsConfigureState.value == RcsConfigureState.CONFIGURED) {
|
|
|
- break
|
|
|
- }
|
|
|
- delay(1000)
|
|
|
- }
|
|
|
- true
|
|
|
- } ?: false
|
|
|
- if (configured) {
|
|
|
- return true
|
|
|
- } else {
|
|
|
- Log.e(TAG, "verifyOtp fail, retrying...")
|
|
|
- return false
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-// suspendCancellableCoroutine<Unit> { continuation ->
|
|
|
-// val observer = Observer<RcsConfigureState> { value ->
|
|
|
-// if (value == expectedValue) {
|
|
|
-// continuation.resume(Unit)
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// observeForever(observer)
|
|
|
-//
|
|
|
-// continuation.invokeOnCancellation {
|
|
|
-// removeObserver(observer)
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
val configured = run a@{
|
|
|
repeat(2) {
|
|
|
sendBroadcast(intent)
|
|
|
- val configured = withTimeoutOrNull(60.seconds) {
|
|
|
- while (true) {
|
|
|
- if (rcsConfigureState.value == RcsConfigureState.CONFIGURED) {
|
|
|
- break
|
|
|
- }
|
|
|
- delay(1000)
|
|
|
- }
|
|
|
- true
|
|
|
- } ?: false
|
|
|
- if (configured) {
|
|
|
+ val state =
|
|
|
+ waitForRcsState(
|
|
|
+ arrayOf(
|
|
|
+ RcsConfigureState.CONFIGURED,
|
|
|
+ RcsConfigureState.RETRY
|
|
|
+ ), 60.seconds
|
|
|
+ )
|
|
|
+ if (state == RcsConfigureState.CONFIGURED) {
|
|
|
return@a true
|
|
|
+ } else if (state == RcsConfigureState.RETRY) {
|
|
|
+ waitForRcsState(
|
|
|
+ arrayOf(RcsConfigureState.WAITING_FOR_OTP),
|
|
|
+ 60.seconds
|
|
|
+ )
|
|
|
} else {
|
|
|
Log.e(TAG, "verifyOtp fail, retrying...")
|
|
|
}
|
|
|
@@ -804,4 +827,6 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
Log.e(TAG, "requestNumber failed")
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
}
|