|
|
@@ -1,4 +1,4 @@
|
|
|
-package com.example.modifier
|
|
|
+package com.example.modifier.service
|
|
|
|
|
|
import android.accessibilityservice.AccessibilityService
|
|
|
import android.accessibilityservice.AccessibilityServiceInfo
|
|
|
@@ -18,20 +18,36 @@ import android.view.accessibility.AccessibilityEvent
|
|
|
import android.view.accessibility.AccessibilityNodeInfo
|
|
|
import android.widget.CompoundButton
|
|
|
import android.widget.FrameLayout
|
|
|
+import androidx.lifecycle.MutableLiveData
|
|
|
+import androidx.lifecycle.liveData
|
|
|
+import com.example.modifier.BuildConfig
|
|
|
+import com.example.modifier.Global
|
|
|
import com.example.modifier.Global.load
|
|
|
+import com.example.modifier.R
|
|
|
+import com.example.modifier.TraverseResult
|
|
|
+import com.example.modifier.Utils
|
|
|
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.response.RcsNumberResponse
|
|
|
+import com.example.modifier.model.TelephonyConfig
|
|
|
import com.google.android.material.color.DynamicColors
|
|
|
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
|
-import com.google.android.material.dialog.MaterialDialogs
|
|
|
+import io.ktor.client.call.body
|
|
|
+import io.ktor.client.plugins.resources.get
|
|
|
+import io.ktor.client.plugins.resources.put
|
|
|
+import io.ktor.http.ContentType
|
|
|
+import io.ktor.http.contentType
|
|
|
import io.socket.client.IO
|
|
|
import io.socket.client.Socket
|
|
|
import io.socket.emitter.Emitter
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
-import kotlinx.coroutines.GlobalScope
|
|
|
-import kotlinx.coroutines.MainScope
|
|
|
+import kotlinx.coroutines.delay
|
|
|
import kotlinx.coroutines.launch
|
|
|
+import kotlinx.coroutines.runBlocking
|
|
|
import kotlinx.coroutines.withContext
|
|
|
+import org.apache.commons.lang3.RandomStringUtils
|
|
|
import org.apache.commons.lang3.StringUtils
|
|
|
import org.json.JSONArray
|
|
|
import org.json.JSONException
|
|
|
@@ -45,6 +61,15 @@ import kotlin.math.max
|
|
|
import kotlin.math.min
|
|
|
|
|
|
class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
+ companion object {
|
|
|
+ private const val TAG = "ModifierService"
|
|
|
+
|
|
|
+ const val NAME: String = BuildConfig.APPLICATION_ID + ".service.ModifierService"
|
|
|
+
|
|
|
+ @JvmStatic
|
|
|
+ var instance: ModifierService? = null
|
|
|
+ private set
|
|
|
+ }
|
|
|
|
|
|
private val mExecutor: ScheduledExecutorService = ScheduledThreadPoolExecutor(8)
|
|
|
|
|
|
@@ -57,6 +82,56 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
private var cleanCount = 0
|
|
|
private var lastSend = 0L
|
|
|
private var rcsInterval = 0L
|
|
|
+ private var requestNumberInterval = 0
|
|
|
+
|
|
|
+ private val rcsConfigureState = MutableLiveData(RcsConfigureState.CONFIGURED)
|
|
|
+
|
|
|
+ private var sendCount: Int
|
|
|
+ get() {
|
|
|
+ return getSharedPreferences(
|
|
|
+ BuildConfig.APPLICATION_ID,
|
|
|
+ MODE_PRIVATE
|
|
|
+ ).getInt("sendCount", 0)
|
|
|
+ }
|
|
|
+ set(value) {
|
|
|
+ getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit()
|
|
|
+ .putInt("sendCount", value).apply()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ val logcat = liveData(Dispatchers.IO) {
|
|
|
+ try {
|
|
|
+ val p = Runtime.getRuntime().exec("su")
|
|
|
+ p.outputStream.bufferedWriter().use { writer ->
|
|
|
+ writer.write("logcat -c")
|
|
|
+ writer.newLine()
|
|
|
+ writer.flush()
|
|
|
+ writer.write("logcat BugleRcsEngine:D *:S -v tag")
|
|
|
+ writer.newLine()
|
|
|
+ writer.flush()
|
|
|
+ }
|
|
|
+ p.inputStream
|
|
|
+ .bufferedReader()
|
|
|
+ .useLines { lines ->
|
|
|
+ Log.d(TAG, "logcat new lines")
|
|
|
+ lines.forEach { line ->
|
|
|
+ emit(line)
|
|
|
+ if (line.contains("destState=CheckPreconditionsState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
|
|
|
+ } else if (line.contains("destState=WaitingForOtpState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_OTP)
|
|
|
+ } else if (line.contains("destState=VerifyOtpState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.VERIFYING_OTP)
|
|
|
+ } else if (line.contains("destState=ConfiguredState")) {
|
|
|
+ rcsConfigureState.postValue(RcsConfigureState.CONFIGURED)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e: Exception) {
|
|
|
+ e.printStackTrace()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private var busy: Boolean
|
|
|
get() {
|
|
|
return _busy
|
|
|
@@ -151,10 +226,11 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
val rcsWait = config.optLong("rcsWait", 2000)
|
|
|
cleanCount = config.optInt("cleanCount", 20)
|
|
|
rcsInterval = config.optLong("rcsInterval", 0)
|
|
|
- counter = 0
|
|
|
+ requestNumberInterval = config.optInt("requestNumberInterval", 0)
|
|
|
val tasks = data.optJSONArray("tasks")
|
|
|
mExecutor.submit {
|
|
|
busy = true
|
|
|
+
|
|
|
val success = JSONArray()
|
|
|
val fail = JSONArray()
|
|
|
for (i in 0 until tasks.length()) {
|
|
|
@@ -185,6 +261,12 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
} catch (e: JSONException) {
|
|
|
}
|
|
|
mSocket.emit("callback", res)
|
|
|
+ if (requestNumberInterval in 1..sendCount) {
|
|
|
+ runBlocking {
|
|
|
+ requestNumber()
|
|
|
+ }
|
|
|
+ sendCount = 0
|
|
|
+ }
|
|
|
busy = false
|
|
|
}
|
|
|
}
|
|
|
@@ -201,6 +283,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
Log.i(TAG, "Command executed successfully, waiting for app to open...")
|
|
|
val f = mExecutor.schedule<Boolean>(
|
|
|
{
|
|
|
+ var success = false
|
|
|
val ts = System.currentTimeMillis()
|
|
|
while (System.currentTimeMillis() - ts < rcsWait) {
|
|
|
val root = rootInActiveWindow
|
|
|
@@ -220,14 +303,9 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
result.sendBtn.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
|
|
lastSend = System.currentTimeMillis()
|
|
|
- counter++
|
|
|
- if (counter >= cleanCount) {
|
|
|
- counter = 0
|
|
|
- Thread.sleep(2000)
|
|
|
- Global.clearConv();
|
|
|
- Thread.sleep(2000)
|
|
|
- }
|
|
|
- return@schedule true
|
|
|
+ success = true
|
|
|
+ sendCount++
|
|
|
+ break
|
|
|
}
|
|
|
} else {
|
|
|
Log.i(TAG, "RCS not detected")
|
|
|
@@ -238,7 +316,15 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
e.printStackTrace()
|
|
|
}
|
|
|
}
|
|
|
- false
|
|
|
+ counter++
|
|
|
+ Log.i(TAG, "sendCount: $sendCount, Counter: $counter, cleanCount: $cleanCount")
|
|
|
+ if (cleanCount in 1..counter) {
|
|
|
+ counter = 0
|
|
|
+ Thread.sleep(2000)
|
|
|
+ Global.clearConv();
|
|
|
+ Thread.sleep(2000)
|
|
|
+ }
|
|
|
+ success
|
|
|
}, 1000, TimeUnit.MILLISECONDS
|
|
|
)
|
|
|
synchronized(f) {
|
|
|
@@ -302,9 +388,6 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
|
|
val height = displayMetrics.heightPixels
|
|
|
val width = displayMetrics.widthPixels
|
|
|
- val maxX = width - Utils.dp2px(this, 108)
|
|
|
- val maxY = height - Utils.dp2px(this, 108)
|
|
|
-
|
|
|
|
|
|
val mLayout = FrameLayout(this)
|
|
|
val layoutParams = WindowManager.LayoutParams()
|
|
|
@@ -324,6 +407,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
binding.tvDeviceName.text = Global.name
|
|
|
windowManager.addView(mLayout, layoutParams)
|
|
|
|
|
|
+ val maxX = width - binding.root.measuredWidth
|
|
|
+ val maxY = height - binding.root.measuredHeight
|
|
|
val downX = AtomicReference(0f)
|
|
|
val downY = AtomicReference(0f)
|
|
|
val downParamX = AtomicReference(0)
|
|
|
@@ -380,6 +465,40 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
canSend = isChecked
|
|
|
updateDevice("canSend", canSend)
|
|
|
}
|
|
|
+
|
|
|
+ logcat.observeForever {
|
|
|
+ if (it.contains("destState="))
|
|
|
+ binding.tvLog.text = it
|
|
|
+ }
|
|
|
+ rcsConfigureState.observeForever {
|
|
|
+ when (it) {
|
|
|
+ RcsConfigureState.NOT_CONFIGURED -> {
|
|
|
+ binding.btnReq.isEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ RcsConfigureState.WAITING_FOR_OTP -> {
|
|
|
+ binding.btnReq.isEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ RcsConfigureState.VERIFYING_OTP -> {
|
|
|
+ binding.btnReq.isEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ RcsConfigureState.CONFIGURED -> {
|
|
|
+ binding.btnReq.isEnabled = true
|
|
|
+ }
|
|
|
+
|
|
|
+ RcsConfigureState.CONFIGURING -> {
|
|
|
+ binding.btnReq.isEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ binding.btnReq.setOnClickListener {
|
|
|
+ CoroutineScope(Dispatchers.IO).launch {
|
|
|
+ requestNumber()
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private fun updateDevice(key: String, value: Any) {
|
|
|
@@ -399,13 +518,89 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- companion object {
|
|
|
- private const val TAG = "ModifierService"
|
|
|
+ suspend fun requestNumber() {
|
|
|
+ while (true) {
|
|
|
+ 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
|
|
|
+ }
|
|
|
|
|
|
- const val NAME: String = BuildConfig.APPLICATION_ID + ".ModifierService"
|
|
|
+ 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.stop(gms = true, sms = true)
|
|
|
+ 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")
|
|
|
+ Utils.runAsRoot("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
|
|
|
+ }
|
|
|
+ delay(1000)
|
|
|
+ }
|
|
|
|
|
|
- @JvmStatic
|
|
|
- var instance: ModifierService? = null
|
|
|
- private set
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ 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}")
|
|
|
+ }
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
}
|