x1ongzhu 1 年之前
父節點
當前提交
1d02a68380

+ 1 - 1
app/src/main/java/com/example/modifier/Global.kt

@@ -243,7 +243,7 @@ object Global {
             Utils.copyAssetFolder(context.assets, "bin", File(dataDir, "bin").path)
             Utils.copyAssetFolder(context.assets, "providerDB", File(dataDir, "providerDB").path)
             //                        Utils.runAsRoot("su -c \"\"");
-            Log.i("Modifier", "arch: " + StringUtils.join(Build.SUPPORTED_ABIS, ", "))
+            Log.i("Modifier", "arch: " + Build.SUPPORTED_ABIS.joinToString(", "))
 
             var arch: String? = null
             for (supportedAbi in Build.SUPPORTED_ABIS) {

+ 1 - 1
app/src/main/java/com/example/modifier/http/request/RcsNumberRequest.kt

@@ -3,4 +3,4 @@ package com.example.modifier.http.request
 import kotlinx.serialization.Serializable
 
 @Serializable
-data class RcsNumberRequest(val deviceId: String, val taskId: String)
+data class RcsNumberRequest(val deviceId: String, val taskId: Int)

+ 88 - 8
app/src/main/java/com/example/modifier/service/ModifierService.kt

@@ -26,6 +26,7 @@ import androidx.datastore.preferences.core.Preferences
 import androidx.datastore.preferences.preferencesDataStore
 import androidx.lifecycle.MediatorLiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
 import androidx.lifecycle.liveData
 import com.example.modifier.BuildConfig
 import com.example.modifier.Global
@@ -36,6 +37,7 @@ 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.extension.waitUntilValueIs
 import com.example.modifier.http.KtorClient
 import com.example.modifier.http.RcsNumberApi
 import com.example.modifier.http.request.RcsNumberRequest
@@ -56,8 +58,10 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeoutOrNull
+import org.apache.commons.collections4.queue.CircularFifoQueue
 import org.apache.commons.lang3.RandomStringUtils
 import org.apache.commons.lang3.StringUtils
 import org.json.JSONArray
@@ -68,6 +72,7 @@ import java.util.concurrent.ScheduledExecutorService
 import java.util.concurrent.ScheduledThreadPoolExecutor
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.atomic.AtomicReference
+import kotlin.coroutines.resume
 import kotlin.math.max
 import kotlin.math.min
 import kotlin.time.Duration.Companion.hours
@@ -152,12 +157,13 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
 
     private val logcat = liveData(Dispatchers.IO) {
         try {
+            val logs = CircularFifoQueue<String>(128)
             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.write("logcat BugleRcsEngine:D *:S -v time")
                 writer.newLine()
                 writer.flush()
             }
@@ -166,7 +172,6 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                 .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")) {
@@ -178,6 +183,22 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                         } else if (line.contains("destState=WaitingForRcsDefaultOnState")) {
                             rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_DEFAULT_ON)
                         }
+                        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)
+                            val log = groups["log"]?.value
+                                ?.replace(Regex("\\[\\w+-\\w+-\\w+-\\w+-\\w+]"), "")
+                                ?.replace(Regex("\\[CONTEXT.*]"), "")
+                                ?.trim()
+
+                            if (time != null && log != null) {
+                                if (log.contains("destState=")) {
+                                    logs.add("$time: $log")
+                                    emit(logs.joinToString("\n"))
+                                }
+                            }
+                        }
                     }
                 }
         } catch (e: Exception) {
@@ -252,7 +273,6 @@ 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)
                     }
@@ -270,6 +290,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
         rcsInterval = config.optLong("rcsInterval", 0)
         requestNumberInterval = config.optInt("requestNumberInterval", 0)
         val tasks = data.optJSONArray("tasks")!!
+        currentTaskId = data.optInt("taskId", 0)
         mExecutor.submit {
             running.postValue(true)
 
@@ -524,8 +545,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
         }
 
         logcat.observeForever {
-            if (it.contains("destState="))
-                binding.tvLog.text = it
+            binding.tvLog.text = it
+            binding.scroll.fullScroll(View.FOCUS_DOWN)
         }
         requesting.observeForever {
             binding.btnReq.isEnabled = !it
@@ -578,6 +599,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                         withContext(Dispatchers.Main) {
                             binding.tvLog.text = "Waiting for logs..."
                         }
+                        rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
                         resetAll()
                         val switchAppear = withTimeoutOrNull(60.seconds) {
                             while (true) {
@@ -626,7 +648,7 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                         setBody(
                             RcsNumberRequest(
                                 deviceId = Utils.getUniqueID(),
-                                taskId = currentTaskId.toString()
+                                taskId = currentTaskId
                             )
                         )
                     }
@@ -709,8 +731,66 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                         "message",
                         "Your Messenger verification code is G-$otp"
                     )
-                    sendBroadcast(intent)
-                    break
+
+                    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(30.seconds) {
+                                while (true) {
+                                    if (rcsConfigureState.value == RcsConfigureState.CONFIGURED) {
+                                        break
+                                    }
+                                    delay(1000)
+                                }
+                                true
+                            } ?: false
+                            if (configured) {
+                                return@a true
+                            } else {
+                                Log.e(TAG, "verifyOtp fail, retrying...")
+                            }
+                        }
+                        false
+                    }
+                    if (!configured) {
+                        Log.e(TAG, "RCS not configured, retrying...")
+                        continue
+                    } else {
+                        break
+                    }
                 }
             }
             true

+ 15 - 10
app/src/main/res/layout/floating_window.xml

@@ -4,8 +4,8 @@
 
     <FrameLayout
         android:id="@+id/floating_window"
-        android:layout_width="208dp"
-        android:layout_height="208dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:orientation="vertical">
 
         <com.google.android.material.card.MaterialCardView
@@ -13,7 +13,7 @@
             android:layout_width="200dp"
             android:layout_height="200dp"
             android:layout_gravity="center"
-            android:alpha="0.7">
+            android:alpha="0.8">
 
             <androidx.constraintlayout.widget.ConstraintLayout
                 android:layout_width="match_parent"
@@ -44,16 +44,21 @@
                     app:layout_constraintStart_toStartOf="@id/sw_connect"
                     app:layout_constraintTop_toBottomOf="@id/sw_connect" />
 
-                <TextView
-                    android:id="@+id/tv_log"
+                <ScrollView
+                    android:id="@+id/scroll"
                     android:layout_width="match_parent"
                     android:layout_height="0dp"
-                    android:ellipsize="start"
-                    android:paddingStart="8dp"
-                    android:paddingEnd="8dp"
-                    android:textSize="12sp"
                     app:layout_constraintBottom_toTopOf="@id/btns"
-                    app:layout_constraintTop_toBottomOf="@id/sw_send" />
+                    app:layout_constraintTop_toBottomOf="@id/sw_send">
+
+                    <TextView
+                        android:id="@+id/tv_log"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:paddingStart="8dp"
+                        android:paddingEnd="8dp"
+                        android:textSize="12sp" />
+                </ScrollView>
 
                 <LinearLayout
                     android:id="@+id/btns"