x1ongzhu 1 год назад
Родитель
Сommit
d018131c10

BIN
app/src/main/assets/providerDB/mmssms.db


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

@@ -241,6 +241,7 @@ object Global {
         try {
             val dataDir = ContextCompat.getDataDir(context)
             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, ", "))
 
@@ -259,11 +260,14 @@ object Global {
                     suspend(sms = true)
 
                     val binPath = File(dataDir, "bin/sqlite3.$arch").path
+                    val providerDBPath = File(dataDir, "providerDB/mmssms.db").path
                     Log.i("Modifier", "sqlite3 binPath: $binPath")
                     Utils.runAsRoot(
                         "chmod +x $binPath",
                         "$binPath /data/data/com.google.android.apps.messaging/databases/bugle_db \"DELETE FROM conversations;\"",
                         "$binPath /data/data/com.google.android.apps.messaging/databases/bugle_db \"DELETE FROM messages;\"",
+                        "cp $providerDBPath /data/data/com.android.providers.telephony/databases/mmssms.db",
+                        "chmod 660 /data/data/com.android.providers.telephony/databases/mmssms.db",
                         "echo ok"
                     )
                     unsuspend(sms = true)
@@ -287,4 +291,28 @@ object Global {
             e.printStackTrace()
         }
     }
+
+    @JvmStatic
+    fun resetAll() {
+        try {
+            Utils.runAsRoot(
+                "pm suspend com.google.android.apps.messaging",
+                "am force-stop com.google.android.apps.messaging",
+                "pm clear com.google.android.apps.messaging",
+                "pm clear com.google.android.gsf",
+                "pm clear com.google.android.gms",
+                "sleep 1",
+                "am start com.android.vending",
+                "sleep 1",
+                "input keyevent KEYCODE_HOME",
+                "sleep 10",
+                "pm clear com.google.android.gms",
+                "pm unsuspend com.google.android.apps.messaging",
+                "sleep 1",
+                "am start com.google.android.apps.messaging"
+            )
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+    }
 }

+ 10 - 0
app/src/main/java/com/example/modifier/TraverseResult.java

@@ -9,6 +9,8 @@ public class TraverseResult {
 
     private AccessibilityNodeInfo sendBtn;
 
+    private AccessibilityNodeInfo rcsSwitch;
+
 
     public boolean isRcsCapable() {
         return rcsCapable;
@@ -25,4 +27,12 @@ public class TraverseResult {
     public void setSendBtn(AccessibilityNodeInfo sendBtn) {
         this.sendBtn = sendBtn;
     }
+
+    public AccessibilityNodeInfo getRcsSwitch() {
+        return rcsSwitch;
+    }
+
+    public void setRcsSwitch(AccessibilityNodeInfo rcsSwitch) {
+        this.rcsSwitch = rcsSwitch;
+    }
 }

+ 1 - 0
app/src/main/java/com/example/modifier/enums/RcsConfigureState.kt

@@ -2,6 +2,7 @@ package com.example.modifier.enums
 
 enum class RcsConfigureState {
     NOT_CONFIGURED,
+    WAITING_FOR_DEFAULT_ON,
     WAITING_FOR_OTP,
     VERIFYING_OTP,
     CONFIGURING,

+ 101 - 20
app/src/main/java/com/example/modifier/service/ModifierService.kt

@@ -5,6 +5,7 @@ import android.accessibilityservice.AccessibilityServiceInfo
 import android.annotation.SuppressLint
 import android.content.Intent
 import android.graphics.PixelFormat
+import android.graphics.Rect
 import android.net.Uri
 import android.os.Build
 import android.util.DisplayMetrics
@@ -23,6 +24,7 @@ import androidx.lifecycle.liveData
 import com.example.modifier.BuildConfig
 import com.example.modifier.Global
 import com.example.modifier.Global.load
+import com.example.modifier.Global.resetAll
 import com.example.modifier.R
 import com.example.modifier.TraverseResult
 import com.example.modifier.Utils
@@ -98,6 +100,18 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                 .putInt("sendCount", value).apply()
         }
 
+    private var requestNumberCount: Int
+        get() {
+            return getSharedPreferences(
+                BuildConfig.APPLICATION_ID,
+                MODE_PRIVATE
+            ).getInt("requestNumberCount", 0)
+        }
+        set(value) {
+            getSharedPreferences(BuildConfig.APPLICATION_ID, MODE_PRIVATE).edit()
+                .putInt("requestNumberCount", value).apply()
+        }
+
 
     val logcat = liveData(Dispatchers.IO) {
         try {
@@ -124,6 +138,8 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                             rcsConfigureState.postValue(RcsConfigureState.VERIFYING_OTP)
                         } else if (line.contains("destState=ConfiguredState")) {
                             rcsConfigureState.postValue(RcsConfigureState.CONFIGURED)
+                        } else if (line.contains("destState=WaitingForRcsDefaultOnState")) {
+                            rcsConfigureState.postValue(RcsConfigureState.WAITING_FOR_DEFAULT_ON)
                         }
                     }
                 }
@@ -317,7 +333,10 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
                         }
                     }
                     counter++
-                    Log.i(TAG, "sendCount: $sendCount, Counter: $counter, cleanCount: $cleanCount")
+                    Log.i(
+                        TAG,
+                        "sendCount: $sendCount, Counter: $counter, cleanCount: $cleanCount, requestNumberInterval: $requestNumberInterval"
+                    )
                     if (cleanCount in 1..counter) {
                         counter = 0
                         Thread.sleep(2000)
@@ -362,6 +381,23 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
             result.isRcsCapable = true
         }
 
+        if (text != null && (text.contains("Turn on RCS chats") || text.contains("开启 RCS 聊天功能"))) {
+            fun findSwitch(node: AccessibilityNodeInfo): Boolean {
+                if ("com.google.android.apps.messaging:id/switchWidget" == node.viewIdResourceName) {
+                    result.rcsSwitch = node
+                    return true
+                }
+                for (i in 0 until node.childCount) {
+                    val child = node.getChild(i)
+                    if (findSwitch(child)) {
+                        return true
+                    }
+                }
+                return false
+            }
+            findSwitch(node.parent.parent)
+        }
+
         if (node.childCount != 0) {
             for (i in 0 until node.childCount) {
                 traverseNode(node.getChild(i), result)
@@ -442,7 +478,6 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
             false
         }
 
-
         binding.swConnect.isChecked = true
         binding.swConnect.setOnCheckedChangeListener { buttonView: CompoundButton?, isChecked: Boolean ->
             if (isChecked) {
@@ -472,33 +507,24 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
         }
         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
-                }
-
+                else -> {}
             }
         }
         binding.btnReq.setOnClickListener {
+            requestNumberCount = 6
             CoroutineScope(Dispatchers.IO).launch {
                 requestNumber()
             }
         }
+        binding.btnInspect.setOnClickListener {
+            CoroutineScope(Dispatchers.IO).launch {
+                traverseNode(getRootInActiveWindow(), TraverseResult())
+            }
+        }
     }
 
     private fun updateDevice(key: String, value: Any) {
@@ -519,7 +545,60 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
     }
 
     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
+
+                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)
+                            }
+                            break
+                        }
+                        if (System.currentTimeMillis() - time > 60000) {
+                            Log.e(TAG, "rcsConfigureState not changed in 60 seconds")
+                            break
+                        } else {
+                            delay(3000)
+                        }
+                    }
+                    if (resetSuccess) {
+                        break
+                    }
+                }
+
+            }
             lateinit var rcsRes: RcsNumberResponse
             rcsConfigureState.postValue(RcsConfigureState.NOT_CONFIGURED)
             try {
@@ -550,8 +629,10 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
             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")
+            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()

+ 7 - 1
app/src/main/java/com/example/modifier/ui/utils/UtilsFragment.kt

@@ -10,6 +10,7 @@ import android.view.ViewGroup
 import androidx.fragment.app.Fragment
 import com.example.modifier.Global.clear
 import com.example.modifier.Global.clearConv
+import com.example.modifier.Global.resetAll
 import com.example.modifier.Global.suspend
 import com.example.modifier.Global.unsuspend
 import com.example.modifier.R
@@ -131,10 +132,15 @@ class UtilsFragment : Fragment() {
         binding.btnClear.isEnabled = false
         Utils.makeLoadingButton(context, binding.btnClear)
         executor.execute {
+            val all = binding.cbAll.isChecked
             val gsf = binding.cbGsf.isChecked
             val gms = binding.cbGms.isChecked
             val sms = binding.cbSms.isChecked
-            clear(gsf, gms, sms)
+            if (all) {
+                resetAll()
+            } else {
+                clear(gsf, gms, sms)
+            }
             handler.post {
                 binding.btnClear.setIconResource(R.drawable.ic_done)
                 binding.btnClear.text = "OK"

+ 26 - 9
app/src/main/res/layout/floating_window.xml

@@ -62,17 +62,34 @@
                     android:textSize="12sp"
                     app:layout_constraintTop_toBottomOf="@id/sw_send" />
 
-                <com.google.android.material.button.MaterialButton
-                    android:id="@+id/btn_req"
-                    android:layout_width="50dp"
-                    android:layout_height="30dp"
-                    android:padding="0dp"
-                    app:icon="@drawable/ic_download"
-                    app:iconGravity="textStart"
-                    app:iconPadding="0dp"
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toStartOf="parent" />
+                    app:layout_constraintStart_toStartOf="parent">
+
+                    <com.google.android.material.button.MaterialButton
+                        android:id="@+id/btn_req"
+                        android:layout_width="50dp"
+                        android:layout_height="30dp"
+                        android:padding="0dp"
+                        app:icon="@drawable/ic_download"
+                        app:iconGravity="textStart"
+                        app:iconPadding="0dp" />
+
+                    <com.google.android.material.button.MaterialButton
+                        android:id="@+id/btn_inspect"
+                        android:layout_width="50dp"
+                        android:layout_height="30dp"
+                        android:layout_marginLeft="8dp"
+                        android:padding="0dp"
+                        android:visibility="gone"
+                        app:icon="@drawable/ic_signal_cellular"
+                        app:iconGravity="textStart"
+                        app:iconPadding="0dp" />
+                </LinearLayout>
 
             </androidx.constraintlayout.widget.ConstraintLayout>
 

+ 6 - 0
app/src/main/res/layout/fragment_utils.xml

@@ -47,6 +47,12 @@
                             android:gravity="center"
                             android:orientation="horizontal">
 
+                            <CheckBox
+                                android:id="@+id/cb_all"
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:text="ALL" />
+
                             <CheckBox
                                 android:id="@+id/cb_gsf"
                                 android:layout_width="wrap_content"