|
|
@@ -13,7 +13,6 @@ import android.os.Handler
|
|
|
import android.os.Looper
|
|
|
import android.util.DisplayMetrics
|
|
|
import android.util.Log
|
|
|
-import android.util.TypedValue
|
|
|
import android.view.Gravity
|
|
|
import android.view.LayoutInflater
|
|
|
import android.view.MotionEvent
|
|
|
@@ -25,7 +24,6 @@ import android.view.accessibility.AccessibilityNodeInfo
|
|
|
import android.widget.CompoundButton
|
|
|
import android.widget.FrameLayout
|
|
|
import androidx.core.content.ContextCompat
|
|
|
-import androidx.core.view.ViewCompat
|
|
|
import androidx.datastore.core.DataStore
|
|
|
import androidx.datastore.preferences.core.Preferences
|
|
|
import androidx.datastore.preferences.preferencesDataStore
|
|
|
@@ -41,13 +39,11 @@ import com.example.modifier.CMD_RCS_SETTINGS_ACTIVITY
|
|
|
import com.example.modifier.Global
|
|
|
import com.example.modifier.Global.load
|
|
|
import com.example.modifier.Global.resetAll
|
|
|
-import com.example.modifier.MyApplication
|
|
|
import com.example.modifier.R
|
|
|
import com.example.modifier.TraverseResult
|
|
|
import com.example.modifier.Utils
|
|
|
import com.example.modifier.data.AppDatabase
|
|
|
-import com.example.modifier.data.BackupItemsRepository
|
|
|
-import com.example.modifier.data.OfflineItemsRepository
|
|
|
+import com.example.modifier.data.BackupItemDao
|
|
|
import com.example.modifier.databinding.FloatingWindowBinding
|
|
|
import com.example.modifier.enums.RcsConfigureState
|
|
|
import com.example.modifier.enums.RcsConnectionStatus
|
|
|
@@ -61,6 +57,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.ui.shellRun
|
|
|
import com.google.android.material.color.DynamicColors
|
|
|
import io.ktor.client.call.body
|
|
|
import io.ktor.client.plugins.resources.get
|
|
|
@@ -76,7 +73,6 @@ 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.withTimeoutOrNull
|
|
|
@@ -87,9 +83,6 @@ import org.apache.commons.lang3.RandomStringUtils
|
|
|
import org.json.JSONException
|
|
|
import org.json.JSONObject
|
|
|
import java.time.LocalDateTime
|
|
|
-import java.time.ZoneId
|
|
|
-import java.time.ZoneOffset
|
|
|
-import java.time.ZonedDateTime
|
|
|
import java.time.temporal.ChronoUnit
|
|
|
import java.util.Optional
|
|
|
import java.util.Timer
|
|
|
@@ -249,8 +242,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private val backupItemsRepository: BackupItemsRepository by lazy {
|
|
|
- (application as MyApplication).container.itemsRepository
|
|
|
+ private val backupItemDao: BackupItemDao by lazy {
|
|
|
+ AppDatabase.getDatabase(this).itemDao()
|
|
|
}
|
|
|
|
|
|
fun connect() {
|
|
|
@@ -292,7 +285,6 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
override fun onCreate() {
|
|
|
super.onCreate()
|
|
|
Log.i(TAG, "Starting ModifierService")
|
|
|
@@ -701,23 +693,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
binding.btnInspect.setOnClickListener {
|
|
|
- CoroutineScope(Dispatchers.IO).launch {
|
|
|
- val res = TraverseResult()
|
|
|
- traverseNode(rootInActiveWindow, res)
|
|
|
- if (res.rcsSwitch != null) {
|
|
|
- Log.i(TAG, "RCS switch isChecked: ${res.rcsSwitch!!.isChecked}")
|
|
|
- Log.i(TAG, "Clicking RCS switch")
|
|
|
- val rect = Rect()
|
|
|
- res.rcsSwitch!!.getBoundsInScreen(rect)
|
|
|
- Utils.runAsRoot(
|
|
|
- "input tap ${rect.centerX()} ${rect.centerY()}",
|
|
|
- "sleep 1",
|
|
|
- CMD_BACK, "sleep 1",
|
|
|
- CMD_RCS_SETTINGS_ACTIVITY, "sleep 1",
|
|
|
- )
|
|
|
- traverseNode(rootInActiveWindow, res)
|
|
|
- Log.i(TAG, "RCS switch isChecked: ${res.rcsSwitch!!.isChecked}")
|
|
|
- }
|
|
|
+ CoroutineScope(Dispatchers.IO).launch {
|
|
|
+ toggleRcsSwitch(false)
|
|
|
}
|
|
|
}
|
|
|
binding.btnCheck.setOnClickListener {
|
|
|
@@ -725,7 +702,11 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
checkRcsAvailability()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ binding.btnStoreNumbers.setOnClickListener {
|
|
|
+ CoroutineScope(Dispatchers.IO).launch {
|
|
|
+ storeNumbers()
|
|
|
+ }
|
|
|
+ }
|
|
|
busy.observeForever {
|
|
|
reportDeviceStatues()
|
|
|
}
|
|
|
@@ -778,6 +759,51 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
return state
|
|
|
}
|
|
|
|
|
|
+ private suspend fun toggleRcsSwitch(on: Boolean, retry: Int = 3): Boolean {
|
|
|
+ val res = TraverseResult()
|
|
|
+
|
|
|
+ val success = run {
|
|
|
+ shellRun(CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
|
|
|
+ repeat(retry) {
|
|
|
+ res.rcsSwitch = null
|
|
|
+ traverseNode(rootInActiveWindow, res)
|
|
|
+ if (res.rcsSwitch == null) {
|
|
|
+ shellRun(CMD_BACK, "sleep 2", CMD_RCS_SETTINGS_ACTIVITY, "sleep 1")
|
|
|
+ } else {
|
|
|
+ if (res.rcsSwitch!!.isChecked == on) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ val rect = Rect()
|
|
|
+ res.rcsSwitch!!.getBoundsInScreen(rect)
|
|
|
+ if (on) {
|
|
|
+ shellRun(
|
|
|
+ "input tap ${rect.centerX()} ${rect.centerY()}",
|
|
|
+ "sleep 1", CMD_BACK, "sleep 1",
|
|
|
+ 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 1", CMD_BACK, "sleep 1",
|
|
|
+ CMD_RCS_SETTINGS_ACTIVITY, "sleep 1",
|
|
|
+ )
|
|
|
+ }
|
|
|
+ traverseNode(rootInActiveWindow, res)
|
|
|
+ if (res.rcsSwitch!!.isChecked == on) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ false
|
|
|
+ }
|
|
|
+ shellRun(CMD_BACK, "sleep 1")
|
|
|
+ return success
|
|
|
+ }
|
|
|
+
|
|
|
private suspend fun requestNumber() {
|
|
|
val color = ContextCompat.getColorStateList(binding.root.context, R.color.btn_color)
|
|
|
binding.btnReq.backgroundTintList = color
|
|
|
@@ -791,8 +817,10 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
requestNumberCount++
|
|
|
requesting.postValue(true)
|
|
|
+
|
|
|
var requestSuccess = false
|
|
|
withTimeoutOrNull(1.hours) {
|
|
|
+ var needRest = false
|
|
|
while (true) {
|
|
|
delay(200)
|
|
|
try {
|
|
|
@@ -835,10 +863,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
)
|
|
|
)
|
|
|
|
|
|
- if (requestNumberCount > 5 && !getSharedPreferences(
|
|
|
- "settings",
|
|
|
- Context.MODE_PRIVATE
|
|
|
- )
|
|
|
+ if (needRest &&
|
|
|
+ !getSharedPreferences("settings", Context.MODE_PRIVATE)
|
|
|
.getBoolean("do_not_reset", false)
|
|
|
) {
|
|
|
val resetSuccess = withTimeoutOrNull(5.minutes) {
|
|
|
@@ -859,37 +885,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
Log.e(TAG, "RCS not entered default on state, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
- Utils.runAsRoot(
|
|
|
- CMD_RCS_SETTINGS_ACTIVITY,
|
|
|
- "sleep 1"
|
|
|
- )
|
|
|
- val res = TraverseResult()
|
|
|
- traverseNode(rootInActiveWindow, res)
|
|
|
- if (res.rcsSwitch == null) {
|
|
|
- Log.e(TAG, "RCS switch not found, retrying...")
|
|
|
- continue
|
|
|
- }
|
|
|
- val switchOn = run turnOnSwitch@{
|
|
|
- repeat(2) {
|
|
|
- if (res.rcsSwitch!!.isChecked) {
|
|
|
- Log.i(TAG, "RCS switch turned on")
|
|
|
- return@turnOnSwitch true
|
|
|
- }
|
|
|
- val rect = Rect()
|
|
|
- res.rcsSwitch!!.getBoundsInScreen(rect)
|
|
|
- Utils.runAsRoot(
|
|
|
- "input tap ${rect.centerX()} ${rect.centerY()}",
|
|
|
- "sleep 1", CMD_BACK, "sleep 1",
|
|
|
- CMD_RCS_SETTINGS_ACTIVITY, "sleep 1",
|
|
|
- )
|
|
|
- traverseNode(rootInActiveWindow, res)
|
|
|
- if (res.rcsSwitch!!.isChecked) {
|
|
|
- Log.i(TAG, "RCS switch turned on")
|
|
|
- return@turnOnSwitch true
|
|
|
- }
|
|
|
- }
|
|
|
- false
|
|
|
- }
|
|
|
+ val switchOn = toggleRcsSwitch(true)
|
|
|
if (!switchOn) {
|
|
|
Log.e(TAG, "RCS switch not turned on, retrying...")
|
|
|
continue
|
|
|
@@ -907,7 +903,9 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
true
|
|
|
} ?: false
|
|
|
- if (!resetSuccess) {
|
|
|
+ if (resetSuccess) {
|
|
|
+ needRest = false
|
|
|
+ } else {
|
|
|
Log.e(TAG, "RCS reset failed, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
@@ -938,6 +936,9 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
) != RcsConfigureState.WAITING_FOR_OTP
|
|
|
) {
|
|
|
Log.e(TAG, "RCS not entered waiting for OTP state, retrying...")
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
continue
|
|
|
}
|
|
|
if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
|
|
|
@@ -1033,30 +1034,32 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private suspend fun checkRcsConnectivity(): Boolean = run checkRcsConnection@{
|
|
|
+ repeat(3) {
|
|
|
+ Log.i(TAG, "Checking RCS status...")
|
|
|
+ shellRun(
|
|
|
+ CMD_CONVERSATION_LIST_ACTIVITY,
|
|
|
+ CMD_RCS_SETTINGS_ACTIVITY,
|
|
|
+ "sleep 1",
|
|
|
+ )
|
|
|
+ val res = TraverseResult()
|
|
|
+ traverseNode(rootInActiveWindow, res)
|
|
|
+ if (res.rcsConnectionStatus == RcsConnectionStatus.CONNECTED) {
|
|
|
+ Log.i(TAG, "RCS is connected")
|
|
|
+ shellRun(CMD_BACK)
|
|
|
+ return@checkRcsConnection true
|
|
|
+ } else {
|
|
|
+ Log.i(TAG, "RCS not connected, retrying...")
|
|
|
+ }
|
|
|
+ shellRun(CMD_BACK, "sleep ${it * 2}")
|
|
|
+ }
|
|
|
+ false
|
|
|
+ }
|
|
|
+
|
|
|
suspend fun checkRcsAvailability(): Boolean {
|
|
|
checkingConnection.postValue(true)
|
|
|
val availability = run checkAvailability@{
|
|
|
- val rcsConnected = run checkRcsConnection@{
|
|
|
- repeat(3) {
|
|
|
- Log.i(TAG, "Checking RCS status...")
|
|
|
- Utils.runAsRoot(
|
|
|
- CMD_CONVERSATION_LIST_ACTIVITY,
|
|
|
- CMD_RCS_SETTINGS_ACTIVITY,
|
|
|
- "sleep 1",
|
|
|
- )
|
|
|
- val res = TraverseResult()
|
|
|
- traverseNode(rootInActiveWindow, res)
|
|
|
- if (res.rcsConnectionStatus == RcsConnectionStatus.CONNECTED) {
|
|
|
- Log.i(TAG, "RCS is connected")
|
|
|
- Utils.runAsRoot(CMD_BACK)
|
|
|
- return@checkRcsConnection true
|
|
|
- } else {
|
|
|
- Log.i(TAG, "RCS not connected, retrying...")
|
|
|
- }
|
|
|
- Utils.runAsRoot(CMD_BACK, "sleep ${it * 2}")
|
|
|
- }
|
|
|
- false
|
|
|
- }
|
|
|
+ val rcsConnected = checkRcsConnectivity()
|
|
|
if (!rcsConnected) {
|
|
|
return@checkAvailability false
|
|
|
}
|
|
|
@@ -1110,4 +1113,18 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
checkingConnection.postValue(false)
|
|
|
return availability
|
|
|
}
|
|
|
+
|
|
|
+ private suspend fun storeNumbers() {
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.btnStoreNumbers.isEnabled = false
|
|
|
+ }
|
|
|
+ repeat(20) {
|
|
|
+ requestNumber()
|
|
|
+ delay(3000)
|
|
|
+ Global.backup(backupItemDao, "auto", 0)
|
|
|
+ }
|
|
|
+ withContext(Dispatchers.Main) {
|
|
|
+ binding.btnStoreNumbers.isEnabled = true
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|