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

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

@@ -7,6 +7,7 @@ import android.os.Build
 import android.util.Log
 import androidx.core.content.ContextCompat
 import com.example.modifier.http.KtorClient
+import com.example.modifier.model.Backup
 import com.example.modifier.model.TelephonyConfig
 import com.example.modifier.ui.shellRun
 import com.example.modifier.utils.RcsHackTool
@@ -23,6 +24,7 @@ import org.apache.commons.lang3.RandomStringUtils
 import org.apache.commons.lang3.StringUtils
 import java.io.File
 import java.io.FileWriter
+import java.nio.file.Files
 import java.time.ZoneId
 import java.time.ZonedDateTime
 import java.time.format.DateTimeFormatter
@@ -520,43 +522,85 @@ object Global {
 
     @SuppressLint("SdCardPath")
     @JvmStatic
-    suspend fun backup(packageName: String, dir: String) {
-        val cmds = mutableListOf("pm suspend $packageName", "am force-stop $packageName")
-
-        if (!shellRun("ls /data/data/$packageName")["error"]!!.contains("No such file or directory")) {
-            cmds.add("cp -r /data/data/$packageName $dir/data")
+    suspend fun backup() {
+        val context = Utils.getContext()
+        val dest = File(
+            ContextCompat.getExternalFilesDirs(context, "backup")[0],
+            System.currentTimeMillis().toString()
+        )
+        dest.mkdirs()
+        val file = File(ContextCompat.getDataDir(context), "config.json")
+        if (!file.exists()) {
+            throw Exception("Config file not found")
+        }
+        withContext(Dispatchers.IO) {
+            IOUtils.copy(
+                Files.newInputStream(file.toPath()),
+                Files.newOutputStream(File(dest, "config.json").toPath())
+            )
         }
-        if (!shellRun("ls /data/user_de/0/$packageName")["error"]!!.contains("No such file or directory")) {
-            cmds.add("cp -r /data/user_de/0/$packageName $dir/user_de")
+        val dataDir = File(dest, "data")
+        dataDir.mkdirs()
+
+        val packages = mutableListOf(
+            "com.google.android.apps.messaging",
+            "com.google.android.gms",
+            "com.google.android.gsf",
+        )
+        packages.forEach {
+            File(dataDir, it).mkdirs()
         }
-        if (!shellRun("ls /sdcard/Android/data/$packageName")["error"]!!.contains("No such file or directory")) {
-            cmds.add("cp -r /sdcard/Android/data/$packageName $dir/external")
+
+        val cmds = mutableListOf<String>()
+        cmds.addAll(packages.flatMap { mutableListOf("pm suspend $it", "am force-stop $it") })
+
+        for (pkg in packages) {
+            if (!shellRun("ls /data/data/$pkg")["error"]!!.contains("No such file or directory")) {
+                cmds.add("cp -r /data/data/$pkg $dataDir/$pkg/data")
+            }
+            if (!shellRun("ls /data/user_de/0/$pkg")["error"]!!.contains("No such file or directory")) {
+                cmds.add("cp -r /data/user_de/0/$pkg $dataDir/$pkg/user_de")
+            }
+            if (!shellRun("ls /sdcard/Android/data/$pkg")["error"]!!.contains("No such file or directory")) {
+                cmds.add("cp -r /sdcard/Android/data/$pkg $dataDir/$pkg/external")
+            }
         }
-        cmds.add("pm unsuspend $packageName")
+
+        cmds.addAll(packages.reversed().map { "pm unsuspend $it" })
         shellRun(*cmds.toTypedArray())
     }
 
     @JvmStatic
-    suspend fun restore(packageName: String, dir: String, uid: Int) {
-        val cmds = mutableListOf("pm suspend $packageName", "am force-stop $packageName")
+    suspend fun restore(backup: Backup) {
+        save(backup.config, false)
+        val packages = mutableListOf(
+            "com.google.android.apps.messaging",
+            "com.google.android.gms",
+            "com.google.android.gsf",
+        )
 
-        if (File("$dir/data").exists()) {
-            cmds.add("rm -rf /data/data/$packageName/*")
-            cmds.add("cp -r $dir/data/* /data/data/$packageName")
-            cmds.add("chown -R $uid:$uid /data/data/$packageName")
-        }
-        if (File("$dir/user_de").exists()) {
-            cmds.add("rm -rf /data/user_de/0/$packageName/*")
-            cmds.add("cp -r $dir/user_de/* /data/user_de/0/$packageName")
-            cmds.add("chown -R $uid:$uid /data/user_de/0/$packageName")
-        }
-        if (File("$dir/external").exists()) {
-            cmds.add("rm -rf /sdcard/Android/data/$packageName/*")
-            cmds.add("cp -r $dir/external/* /sdcard/Android/data/$packageName")
-            cmds.add("chown -R $uid:$uid /sdcard/Android/data/$packageName")
+        val cmds = mutableListOf<String>()
+        cmds.addAll(packages.flatMap { mutableListOf("pm suspend $it", "am force-stop $it") })
+        val packageManager = Utils.getContext().packageManager
+        for (pkg in packages) {
+            val uid = packageManager.getApplicationInfo(pkg, 0).uid
+            if (File("${backup.path}/data/$pkg/data").exists()) {
+                cmds.add("rm -rf /data/data/$pkg/*")
+                cmds.add("cp -r ${backup.path}/data/$pkg/data/* /data/data/$pkg")
+                cmds.add("chown -R $uid:$uid /data/data/$pkg")
+            }
+            if (File("${backup.path}/data/$pkg/user_de").exists()) {
+                cmds.add("rm -rf /data/user_de/0/$pkg/*")
+                cmds.add("cp -r ${backup.path}/data/$pkg/user_de/* /data/user_de/0/$pkg")
+                cmds.add("chown -R $uid:$uid /data/user_de/0/$pkg")
+            }
+            if (File("${backup.path}/data/$pkg/external").exists()) {
+                cmds.add("rm -rf /sdcard/Android/data/$pkg/*")
+                cmds.add("cp -r ${backup.path}/data/$pkg/external/* /sdcard/Android/data/$pkg")
+                cmds.add("chown -R $uid:$uid /sdcard/Android/data/$pkg")
+            }
         }
-
-        cmds.add("pm unsuspend $packageName")
+        cmds.addAll(packages.reversed().map { "pm unsuspend $it" })
         shellRun(*cmds.toTypedArray())
     }
 }

+ 11 - 27
app/src/main/java/com/example/modifier/adapter/BackupAdapter.kt

@@ -21,6 +21,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 import java.io.File
 import java.text.SimpleDateFormat
 
@@ -38,11 +39,11 @@ class BackupAdapter(private val context: Context, private val backups: MutableLi
     @SuppressLint("DefaultLocale")
     override fun onBindViewHolder(holder: BackupViewHolder, position: Int) {
         val backup = backups[position]
-        holder.binding.tvNumber.text = backup.config.number
+        holder.binding.tvNumber.text = "+" + backup.config.areaCode + " " + backup.config.number
         holder.binding.tvTime.text = SimpleDateFormat.getDateTimeInstance().format(backup.date)
         holder.binding.tvInfo.text = String.format(
             "MCC: %s, MNC: %s, Country: %s",
-            backup.config.mcc, backup.config.mcc, backup.config.country
+            backup.config.mcc, backup.config.mnc, backup.config.country
         )
         holder.binding.btnRestore.setOnClickListener { v: View? ->
             MaterialAlertDialogBuilder(
@@ -51,36 +52,19 @@ class BackupAdapter(private val context: Context, private val backups: MutableLi
                 .setTitle("Restore backup")
                 .setMessage("Are you sure you want to restore this backup?")
                 .setPositiveButton("Yes") { dialog: DialogInterface?, which: Int ->
+                    dialog?.dismiss()
+                    Utils.makeLoadingButton(context, holder.binding.btnRestore)
                     CoroutineScope(Dispatchers.IO).launch {
                         try {
-                            save(backup.config, false)
-                            val packageManager = context.packageManager
-                            val uid = packageManager.getApplicationInfo(
-                                "com.google.android.apps.messaging",
-                                0
-                            ).uid
-                            val gmsUid =
-                                packageManager.getApplicationInfo("com.google.android.gms", 0).uid
-                            val gsfUid =
-                                packageManager.getApplicationInfo("com.google.android.gsf", 0).uid
-                            Global.restore(
-                                "com.google.android.apps.messaging",
-                                backup.path + "/data/com.google.android.apps.messaging",
-                                uid
-                            )
-                            Global.restore(
-                                "com.google.android.gms",
-                                backup.path + "/data/com.google.android.gms",
-                                gmsUid
-                            )
-                            Global.restore(
-                                "com.google.android.gsf",
-                                backup.path + "/data/com.google.android.gsf",
-                                gsfUid
-                            )
+                            Global.restore(backup)
                         } catch (e: Exception) {
                             e.printStackTrace()
                         }
+                        withContext(Dispatchers.Main) {
+                            holder.binding.btnRestore.isEnabled = true
+                            holder.binding.btnRestore.text = "Restore"
+                            holder.binding.btnRestore.icon = null
+                        }
                     }
                 }
                 .setNegativeButton("No", null)

+ 1 - 33
app/src/main/java/com/example/modifier/ui/backup/BackupFragment.kt

@@ -94,40 +94,8 @@ class BackupFragment : Fragment() {
 
     private suspend fun createBackup() {
         try {
-            suspend(false, true, true)
-            val backupDir = File(
-                ContextCompat.getExternalFilesDirs(requireContext(), "backup")[0],
-                System.currentTimeMillis().toString() + ""
-            )
-            backupDir.mkdirs()
-            val file = File(ContextCompat.getDataDir(requireContext()), "config.json")
-            if (!file.exists()) {
-                throw Exception("Config file not found")
-            }
-            withContext(Dispatchers.IO) {
-                IOUtils.copy(
-                    Files.newInputStream(file.toPath()),
-                    Files.newOutputStream(File(backupDir, "config.json").toPath())
-                )
-            }
-            val dataDir = File(backupDir, "data")
-            dataDir.mkdirs()
-
-            val gmsDir = File(dataDir, "com.google.android.gms")
-            gmsDir.mkdirs()
-            Global.backup("com.google.android.gms", gmsDir.path)
-
-            val gsfDir = File(dataDir, "com.google.android.gsf")
-            gsfDir.mkdirs()
-            Global.backup("com.google.android.gsf", gsfDir.path)
-
-            val msgDir = File(dataDir, "com.google.android.apps.messaging")
-            msgDir.mkdirs()
-            Global.backup("com.google.android.apps.messaging", msgDir.path)
-
-
+            Global.backup()
             loadBackups()
-
         } catch (e: Exception) {
             e.printStackTrace()
         }

+ 2 - 1
app/src/main/res/layout/fragment_backup.xml

@@ -18,7 +18,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:clipToPadding="false"
-                android:fitsSystemWindows="true">
+                android:paddingTop="40dp"
+                android:paddingBottom="100dp">
 
             </androidx.recyclerview.widget.RecyclerView>
         </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>