|
|
@@ -3,6 +3,7 @@ package com.example.modifier.service
|
|
|
import android.accessibilityservice.AccessibilityService
|
|
|
import android.accessibilityservice.AccessibilityServiceInfo
|
|
|
import android.annotation.SuppressLint
|
|
|
+import android.content.Context
|
|
|
import android.content.Intent
|
|
|
import android.graphics.PixelFormat
|
|
|
import android.graphics.Rect
|
|
|
@@ -14,11 +15,16 @@ import android.view.Gravity
|
|
|
import android.view.LayoutInflater
|
|
|
import android.view.MotionEvent
|
|
|
import android.view.View
|
|
|
+import android.view.View.OnTouchListener
|
|
|
import android.view.WindowManager
|
|
|
import android.view.accessibility.AccessibilityEvent
|
|
|
import android.view.accessibility.AccessibilityNodeInfo
|
|
|
import android.widget.CompoundButton
|
|
|
import android.widget.FrameLayout
|
|
|
+import androidx.datastore.core.DataStore
|
|
|
+import androidx.datastore.preferences.core.Preferences
|
|
|
+import androidx.datastore.preferences.preferencesDataStore
|
|
|
+import androidx.lifecycle.MediatorLiveData
|
|
|
import androidx.lifecycle.MutableLiveData
|
|
|
import androidx.lifecycle.liveData
|
|
|
import com.example.modifier.BuildConfig
|
|
|
@@ -32,12 +38,14 @@ import com.example.modifier.databinding.FloatingWindowBinding
|
|
|
import com.example.modifier.enums.RcsConfigureState
|
|
|
import com.example.modifier.http.KtorClient
|
|
|
import com.example.modifier.http.RcsNumberApi
|
|
|
+import com.example.modifier.http.request.RcsNumberRequest
|
|
|
import com.example.modifier.http.response.RcsNumberResponse
|
|
|
import com.example.modifier.model.TelephonyConfig
|
|
|
import com.google.android.material.color.DynamicColors
|
|
|
import io.ktor.client.call.body
|
|
|
import io.ktor.client.plugins.resources.get
|
|
|
import io.ktor.client.plugins.resources.put
|
|
|
+import io.ktor.client.request.setBody
|
|
|
import io.ktor.http.ContentType
|
|
|
import io.ktor.http.contentType
|
|
|
import io.socket.client.IO
|
|
|
@@ -49,6 +57,7 @@ import kotlinx.coroutines.delay
|
|
|
import kotlinx.coroutines.launch
|
|
|
import kotlinx.coroutines.runBlocking
|
|
|
import kotlinx.coroutines.withContext
|
|
|
+import kotlinx.coroutines.withTimeoutOrNull
|
|
|
import org.apache.commons.lang3.RandomStringUtils
|
|
|
import org.apache.commons.lang3.StringUtils
|
|
|
import org.json.JSONArray
|
|
|
@@ -61,7 +70,12 @@ import java.util.concurrent.TimeUnit
|
|
|
import java.util.concurrent.atomic.AtomicReference
|
|
|
import kotlin.math.max
|
|
|
import kotlin.math.min
|
|
|
+import kotlin.time.Duration.Companion.hours
|
|
|
+import kotlin.time.Duration.Companion.seconds
|
|
|
|
|
|
+val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "serverConfig")
|
|
|
+
|
|
|
+@SuppressLint("SetTextI18n")
|
|
|
class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
companion object {
|
|
|
private const val TAG = "ModifierService"
|
|
|
@@ -75,16 +89,40 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
|
|
|
private val mExecutor: ScheduledExecutorService = ScheduledThreadPoolExecutor(8)
|
|
|
|
|
|
- private lateinit var mSocket: Socket
|
|
|
private val mSocketOpts = IO.Options()
|
|
|
- private var canSend = false
|
|
|
+ private lateinit var mSocket: Socket
|
|
|
private lateinit var binding: FloatingWindowBinding
|
|
|
+
|
|
|
+ private var canSend: Boolean
|
|
|
+ get() {
|
|
|
+ return getSharedPreferences(
|
|
|
+ BuildConfig.APPLICATION_ID,
|
|
|
+ MODE_PRIVATE
|
|
|
+ ).getBoolean("canSend", false)
|
|
|
+ }
|
|
|
+ set(value) {
|
|
|
+ getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit()
|
|
|
+ .putBoolean("canSend", value).apply()
|
|
|
+ reportDeviceStatues()
|
|
|
+ }
|
|
|
private var counter = 0
|
|
|
- private var _busy = false
|
|
|
private var cleanCount = 0
|
|
|
private var lastSend = 0L
|
|
|
private var rcsInterval = 0L
|
|
|
private var requestNumberInterval = 0
|
|
|
+ private val running = MutableLiveData(false)
|
|
|
+ private val requesting = MutableLiveData(false)
|
|
|
+ private var currentTaskId = 0
|
|
|
+
|
|
|
+ private var busy = MediatorLiveData<Boolean>().apply {
|
|
|
+ addSource(running) {
|
|
|
+ value = it || requesting.value!!
|
|
|
+ }
|
|
|
+ addSource(requesting) {
|
|
|
+ value = it || running.value!!
|
|
|
+ }
|
|
|
+ value = requesting.value!! || running.value!!
|
|
|
+ }
|
|
|
|
|
|
private val rcsConfigureState = MutableLiveData(RcsConfigureState.CONFIGURED)
|
|
|
|
|
|
@@ -112,8 +150,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
.putInt("requestNumberCount", value).apply()
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- val logcat = liveData(Dispatchers.IO) {
|
|
|
+ private val logcat = liveData(Dispatchers.IO) {
|
|
|
try {
|
|
|
val p = Runtime.getRuntime().exec("su")
|
|
|
p.outputStream.bufferedWriter().use { writer ->
|
|
|
@@ -148,53 +185,41 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private var busy: Boolean
|
|
|
- get() {
|
|
|
- return _busy
|
|
|
- }
|
|
|
- set(value) {
|
|
|
- _busy = value
|
|
|
- updateDevice("busy", value)
|
|
|
- }
|
|
|
-
|
|
|
fun connect() {
|
|
|
- CoroutineScope(Dispatchers.IO).launch {
|
|
|
- try {
|
|
|
- load()
|
|
|
- if (this@ModifierService::binding.isInitialized) {
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvDeviceName.text = Global.name
|
|
|
- }
|
|
|
- }
|
|
|
- if (this@ModifierService::mSocket.isInitialized) {
|
|
|
- mSocket.disconnect()
|
|
|
- }
|
|
|
- canSend = getSharedPreferences(
|
|
|
- BuildConfig.APPLICATION_ID,
|
|
|
- MODE_PRIVATE
|
|
|
- ).getBoolean("canSend", false)
|
|
|
- mSocketOpts.query =
|
|
|
- "model=" + Build.MANUFACTURER + " " + Build.MODEL + "&name=" + Global.name + "&id=" + Utils.getUniqueID() + "&canSend=" + canSend
|
|
|
- mSocket = IO.socket(Global.serverUrl, mSocketOpts)
|
|
|
- mSocket.on("message", this@ModifierService)
|
|
|
- mSocket.on(Socket.EVENT_CONNECT) {
|
|
|
- Log.i(TAG, "Connected to server")
|
|
|
- }
|
|
|
- mSocket.on(Socket.EVENT_DISCONNECT) {
|
|
|
- Log.i(TAG, "Disconnected from server")
|
|
|
+ try {
|
|
|
+ load()
|
|
|
+ if (this@ModifierService::binding.isInitialized) {
|
|
|
+ binding.swSend.text = Global.name
|
|
|
+ }
|
|
|
+ if (this@ModifierService::mSocket.isInitialized) {
|
|
|
+ mSocket.disconnect()
|
|
|
+ }
|
|
|
+ mSocketOpts.query =
|
|
|
+ "model=${Build.MANUFACTURER} ${Build.MODEL}&name=${Global.name}&id=${Utils.getUniqueID()}"
|
|
|
+ mSocketOpts.transports = arrayOf("websocket")
|
|
|
+ Log.i(TAG, "Connection query: ${mSocketOpts.query}")
|
|
|
+ mSocket = IO.socket(Global.serverUrl, mSocketOpts)
|
|
|
+ mSocket.on("message", this@ModifierService)
|
|
|
+ mSocket.on(Socket.EVENT_CONNECT) {
|
|
|
+ Log.i(TAG, "Connected to server")
|
|
|
+ CoroutineScope(Dispatchers.IO).launch {
|
|
|
+ delay(500)
|
|
|
+ reportDeviceStatues()
|
|
|
}
|
|
|
- mSocket.on(Socket.EVENT_CONNECT_ERROR) { args ->
|
|
|
- Log.i(TAG, "Connection error: " + args[0])
|
|
|
- if (args[0] is Exception) {
|
|
|
- val e = args[0] as Exception
|
|
|
- e.printStackTrace()
|
|
|
- }
|
|
|
+ }
|
|
|
+ mSocket.on(Socket.EVENT_DISCONNECT) {
|
|
|
+ Log.i(TAG, "Disconnected from server")
|
|
|
+ }
|
|
|
+ mSocket.on(Socket.EVENT_CONNECT_ERROR) { args ->
|
|
|
+ Log.i(TAG, "Connection error: " + args[0])
|
|
|
+ if (args[0] is Exception) {
|
|
|
+ val e = args[0] as Exception
|
|
|
+ e.printStackTrace()
|
|
|
}
|
|
|
-
|
|
|
- mSocket.connect()
|
|
|
- } catch (e: Exception) {
|
|
|
- e.printStackTrace()
|
|
|
}
|
|
|
+ mSocket.connect()
|
|
|
+ } catch (e: Exception) {
|
|
|
+ e.printStackTrace()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -227,6 +252,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
} else if ("task" == action) {
|
|
|
val data = json.optJSONObject("data")
|
|
|
val id = json.optString("id")
|
|
|
+ currentTaskId = json.optInt("id", 0)
|
|
|
if (data != null && StringUtils.isNoneBlank(id)) {
|
|
|
runTask(id, data)
|
|
|
}
|
|
|
@@ -243,9 +269,9 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
cleanCount = config.optInt("cleanCount", 20)
|
|
|
rcsInterval = config.optLong("rcsInterval", 0)
|
|
|
requestNumberInterval = config.optInt("requestNumberInterval", 0)
|
|
|
- val tasks = data.optJSONArray("tasks")
|
|
|
+ val tasks = data.optJSONArray("tasks")!!
|
|
|
mExecutor.submit {
|
|
|
- busy = true
|
|
|
+ running.postValue(true)
|
|
|
|
|
|
val success = JSONArray()
|
|
|
val fail = JSONArray()
|
|
|
@@ -281,9 +307,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
runBlocking {
|
|
|
requestNumber()
|
|
|
}
|
|
|
- sendCount = 0
|
|
|
}
|
|
|
- busy = false
|
|
|
+ running.postValue(false)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -304,10 +329,10 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
while (System.currentTimeMillis() - ts < rcsWait) {
|
|
|
val root = rootInActiveWindow
|
|
|
val packageName = root.packageName.toString()
|
|
|
- val result = TraverseResult()
|
|
|
- traverseNode(root, result)
|
|
|
- if (result.isRcsCapable) {
|
|
|
- if (result.sendBtn == null) {
|
|
|
+ val traverseResult = TraverseResult()
|
|
|
+ traverseNode(root, traverseResult)
|
|
|
+ if (traverseResult.isRcsCapable) {
|
|
|
+ if (traverseResult.sendBtn == null) {
|
|
|
Log.i(TAG, "Send button not found")
|
|
|
} else {
|
|
|
Log.i(TAG, "Clicking send button")
|
|
|
@@ -317,7 +342,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
Log.i(TAG, "Waiting for RCS interval")
|
|
|
Thread.sleep(rcsInterval - dt)
|
|
|
}
|
|
|
- result.sendBtn.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
|
|
+ traverseResult.sendBtn.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
|
|
lastSend = System.currentTimeMillis()
|
|
|
success = true
|
|
|
sendCount++
|
|
|
@@ -440,7 +465,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
val newContext = DynamicColors.wrapContextIfAvailable(applicationContext, R.style.AppTheme)
|
|
|
val inflater = LayoutInflater.from(newContext)
|
|
|
binding = FloatingWindowBinding.inflate(inflater, mLayout, true)
|
|
|
- binding.tvDeviceName.text = Global.name
|
|
|
+ binding.swSend.text = Global.name
|
|
|
windowManager.addView(mLayout, layoutParams)
|
|
|
|
|
|
val maxX = width - binding.root.measuredWidth
|
|
|
@@ -450,14 +475,13 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
val downParamX = AtomicReference(0)
|
|
|
val downParamY = AtomicReference(0)
|
|
|
|
|
|
- binding.floatingWindow.setOnTouchListener { v: View?, event: MotionEvent ->
|
|
|
+ var touchListener = OnTouchListener { v, event ->
|
|
|
when (event.action) {
|
|
|
MotionEvent.ACTION_DOWN -> {
|
|
|
downX.set(event.rawX)
|
|
|
downY.set(event.rawY)
|
|
|
downParamX.set(layoutParams.x)
|
|
|
downParamY.set(layoutParams.y)
|
|
|
- return@setOnTouchListener true
|
|
|
}
|
|
|
|
|
|
MotionEvent.ACTION_MOVE -> {
|
|
|
@@ -472,12 +496,17 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
)
|
|
|
.toInt()
|
|
|
windowManager.updateViewLayout(mLayout, layoutParams)
|
|
|
- return@setOnTouchListener true
|
|
|
+ }
|
|
|
+
|
|
|
+ MotionEvent.ACTION_UP -> {
|
|
|
+ return@OnTouchListener event.eventTime - event.downTime >= 200
|
|
|
}
|
|
|
}
|
|
|
false
|
|
|
}
|
|
|
|
|
|
+ binding.swSend.setOnTouchListener(touchListener)
|
|
|
+
|
|
|
binding.swConnect.isChecked = true
|
|
|
binding.swConnect.setOnCheckedChangeListener { buttonView: CompoundButton?, isChecked: Boolean ->
|
|
|
if (isChecked) {
|
|
|
@@ -489,30 +518,17 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- canSend = getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).getBoolean(
|
|
|
- "canSend",
|
|
|
- false
|
|
|
- )
|
|
|
binding.swSend.isChecked = canSend
|
|
|
binding.swSend.setOnCheckedChangeListener { buttonView: CompoundButton?, isChecked: Boolean ->
|
|
|
- getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit()
|
|
|
- .putBoolean("canSend", isChecked).apply()
|
|
|
canSend = isChecked
|
|
|
- updateDevice("canSend", canSend)
|
|
|
}
|
|
|
|
|
|
logcat.observeForever {
|
|
|
if (it.contains("destState="))
|
|
|
binding.tvLog.text = it
|
|
|
}
|
|
|
- rcsConfigureState.observeForever {
|
|
|
- when (it) {
|
|
|
- RcsConfigureState.CONFIGURED -> {
|
|
|
- binding.btnReq.isEnabled = true
|
|
|
- }
|
|
|
-
|
|
|
- else -> {}
|
|
|
- }
|
|
|
+ requesting.observeForever {
|
|
|
+ binding.btnReq.isEnabled = !it
|
|
|
}
|
|
|
binding.btnReq.setOnClickListener {
|
|
|
requestNumberCount = 6
|
|
|
@@ -522,165 +538,190 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
binding.btnInspect.setOnClickListener {
|
|
|
CoroutineScope(Dispatchers.IO).launch {
|
|
|
- traverseNode(getRootInActiveWindow(), TraverseResult())
|
|
|
+ traverseNode(rootInActiveWindow, TraverseResult())
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ busy.observeForever {
|
|
|
+ reportDeviceStatues()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private fun updateDevice(key: String, value: Any) {
|
|
|
+ private fun reportDeviceStatues() {
|
|
|
if (this::mSocket.isInitialized) {
|
|
|
val data = JSONObject()
|
|
|
try {
|
|
|
data.put("action", "updateDevice")
|
|
|
val dataObj = JSONObject()
|
|
|
- dataObj.put(key, value)
|
|
|
+ dataObj.put("canSend", canSend)
|
|
|
+ dataObj.put("busy", busy.value)
|
|
|
data.put("data", dataObj)
|
|
|
-
|
|
|
mSocket.emit("message", data)
|
|
|
-
|
|
|
} catch (e: JSONException) {
|
|
|
e.printStackTrace()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- suspend fun requestNumber() {
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.btnReq.isEnabled = false
|
|
|
- }
|
|
|
- while (true) {
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Waiting for logs..."
|
|
|
- }
|
|
|
- requestNumberCount++
|
|
|
- if (requestNumberCount > 5) {
|
|
|
- requestNumberCount = 0
|
|
|
+ private suspend fun requestNumber() {
|
|
|
+ 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
|
|
|
|
|
|
- while (true) {
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
- binding.tvLog.text = "Waiting for logs..."
|
|
|
- }
|
|
|
- resetAll()
|
|
|
- var resetSuccess = false
|
|
|
- val time = System.currentTimeMillis()
|
|
|
while (true) {
|
|
|
- if (rcsConfigureState.value == RcsConfigureState.WAITING_FOR_DEFAULT_ON) {
|
|
|
- Utils.runAsRoot(
|
|
|
- "am start com.google.android.apps.messaging/com.google.android.apps.messaging.ui.appsettings.RcsSettingsActivity",
|
|
|
- "sleep 1"
|
|
|
- )
|
|
|
- val res = TraverseResult()
|
|
|
- traverseNode(getRootInActiveWindow(), res)
|
|
|
- if (res.rcsSwitch != null) {
|
|
|
- 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",
|
|
|
- )
|
|
|
- resetSuccess = true
|
|
|
- Log.i(TAG, "RCS switch turned on, waiting 60 seconds...")
|
|
|
- delay(60000)
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.tvLog.text = "Waiting for logs..."
|
|
|
+ }
|
|
|
+ resetAll()
|
|
|
+ val switchAppear = withTimeoutOrNull(60.seconds) {
|
|
|
+ while (true) {
|
|
|
+ if (rcsConfigureState.value == RcsConfigureState.WAITING_FOR_DEFAULT_ON) {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ delay(1.seconds)
|
|
|
}
|
|
|
- break
|
|
|
+ true
|
|
|
+ } ?: false
|
|
|
+ if (!switchAppear) {
|
|
|
+ Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
+ continue
|
|
|
}
|
|
|
- if (System.currentTimeMillis() - time > 60000) {
|
|
|
- Log.e(TAG, "rcsConfigureState not changed in 60 seconds")
|
|
|
- break
|
|
|
- } else {
|
|
|
- delay(3000)
|
|
|
+ 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
|
|
|
}
|
|
|
- }
|
|
|
- if (resetSuccess) {
|
|
|
+ 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)
|
|
|
}
|
|
|
- rcsRes = response.body<RcsNumberResponse>()
|
|
|
- Log.i(TAG, "requestNumber response: $rcsRes")
|
|
|
- } catch (exception: Exception) {
|
|
|
- exception.printStackTrace()
|
|
|
- delay(2000)
|
|
|
- continue
|
|
|
- }
|
|
|
+ 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.toString()
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ rcsRes = response.body<RcsNumberResponse>()
|
|
|
+ Log.i(TAG, "requestNumber response: $rcsRes")
|
|
|
+ } catch (exception: Exception) {
|
|
|
+ exception.printStackTrace()
|
|
|
+ delay(2000)
|
|
|
+ continue
|
|
|
+ }
|
|
|
|
|
|
- Global.save(
|
|
|
- TelephonyConfig(
|
|
|
- rcsRes.number,
|
|
|
- rcsRes.mcc,
|
|
|
- rcsRes.mnc,
|
|
|
- RandomStringUtils.randomNumeric(20),
|
|
|
- rcsRes.mcc + rcsRes.mnc + RandomStringUtils.randomNumeric(
|
|
|
- 15 - rcsRes.mcc.length - rcsRes.mnc.length
|
|
|
- ),
|
|
|
- Utils.generateIMEI(),
|
|
|
- rcsRes.country
|
|
|
+ Global.save(
|
|
|
+ TelephonyConfig(
|
|
|
+ rcsRes.number,
|
|
|
+ rcsRes.mcc,
|
|
|
+ rcsRes.mnc,
|
|
|
+ RandomStringUtils.randomNumeric(20),
|
|
|
+ rcsRes.mcc + rcsRes.mnc + RandomStringUtils.randomNumeric(
|
|
|
+ 15 - rcsRes.mcc.length - rcsRes.mnc.length
|
|
|
+ ),
|
|
|
+ Utils.generateIMEI(),
|
|
|
+ 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)
|
|
|
+ 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 time = System.currentTimeMillis()
|
|
|
- while (rcsConfigureState.value != RcsConfigureState.WAITING_FOR_OTP) {
|
|
|
- if (System.currentTimeMillis() - time > 30000) {
|
|
|
- Log.e(TAG, "RCS not configured in 30 seconds")
|
|
|
- break
|
|
|
+ val waitingForOtp = withTimeoutOrNull(30000) {
|
|
|
+ repeat(1000) {
|
|
|
+ if (rcsConfigureState.value == RcsConfigureState.WAITING_FOR_OTP) {
|
|
|
+ return@repeat
|
|
|
+ }
|
|
|
+ delay(1000)
|
|
|
+ }
|
|
|
+ true
|
|
|
+ } ?: false
|
|
|
+
|
|
|
+ if (!waitingForOtp) {
|
|
|
+ Log.e(TAG, "RCS not entered waiting for OTP state, retrying...")
|
|
|
+ continue
|
|
|
}
|
|
|
- delay(1000)
|
|
|
- }
|
|
|
|
|
|
- val otpTime = System.currentTimeMillis()
|
|
|
- while (rcsRes.status != RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
- if (System.currentTimeMillis() - otpTime > 20000) {
|
|
|
- Log.e(TAG, "OTP not received in 20 seconds")
|
|
|
- break
|
|
|
+ withTimeoutOrNull(20000) {
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+ rcsRes = KtorClient.get(RcsNumberApi.Id(id = rcsRes.id))
|
|
|
+ .body<RcsNumberResponse>()
|
|
|
+ Log.i(TAG, "wait for otp response: $rcsRes")
|
|
|
+ if (rcsRes.status == RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } catch (exception: Exception) {
|
|
|
+ Log.e(TAG, "wait for otp Error: ${exception.stackTrace}")
|
|
|
+ }
|
|
|
+ delay(2000)
|
|
|
+ }
|
|
|
}
|
|
|
- try {
|
|
|
- rcsRes = KtorClient.get(RcsNumberApi.Id(id = rcsRes.id))
|
|
|
- .body<RcsNumberResponse>()
|
|
|
- Log.i(TAG, "requestNumber response: $rcsRes")
|
|
|
- } catch (exception: Exception) {
|
|
|
- Log.e(TAG, "requestNumber Error: ${exception.stackTrace}")
|
|
|
+
|
|
|
+ if (rcsRes.status != RcsNumberResponse.STATUS_SUCCESS) {
|
|
|
+ Log.e(TAG, "OTP not received, retrying...")
|
|
|
+ continue
|
|
|
}
|
|
|
- delay(2000)
|
|
|
- }
|
|
|
- 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!!)
|
|
|
- if (match != null) {
|
|
|
- val otp = match.groupValues[1]
|
|
|
- Log.i(TAG, "OTP: $otp")
|
|
|
- val intent = Intent()
|
|
|
- intent.setAction("com.example.modifier.sms")
|
|
|
- intent.putExtra("sender", "3538")
|
|
|
- intent.putExtra(
|
|
|
- "message",
|
|
|
- "Your Messenger verification code is G-$otp"
|
|
|
- )
|
|
|
- sendBroadcast(intent)
|
|
|
- return
|
|
|
+ val match =
|
|
|
+ Regex("Your Messenger verification code is G-(\\d{6})")
|
|
|
+ .matchEntire(rcsRes.message!!)
|
|
|
+ if (match != null) {
|
|
|
+ val otp = match.groupValues[1]
|
|
|
+ Log.i(TAG, "OTP: $otp")
|
|
|
+ val intent = Intent()
|
|
|
+ intent.setAction("com.example.modifier.sms")
|
|
|
+ intent.putExtra("sender", "3538")
|
|
|
+ intent.putExtra(
|
|
|
+ "message",
|
|
|
+ "Your Messenger verification code is G-$otp"
|
|
|
+ )
|
|
|
+ sendBroadcast(intent)
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
+ true
|
|
|
+ } ?: false
|
|
|
+ requesting.postValue(false)
|
|
|
+ if (result) {
|
|
|
+ sendCount = 0
|
|
|
+ counter = 0
|
|
|
+ Log.i(TAG, "requestNumber success")
|
|
|
+ } else {
|
|
|
+ Log.e(TAG, "requestNumber failed")
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|