From f6c1f9d0f6e48821ca9bb9dc2142f12e12d3a7d6 Mon Sep 17 00:00:00 2001 From: HeCodes2Much Date: Tue, 21 May 2024 19:38:27 +0100 Subject: [PATCH] feat: Added Basic Backup / Restore Feature --- app/build.gradle.kts | 3 + .../launcher/helper/AppExtensions.kt | 85 +++++++++++++++++++ .../launcher/helper/AppHelper.kt | 14 ++- .../launcher/ui/settings/SettingsFragment.kt | 21 ++++- app/src/main/res/layout/fragment_settings.xml | 43 ++++++++++ app/src/main/res/values/strings.xml | 7 ++ 6 files changed, 166 insertions(+), 7 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7c6a032..d435c27 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,6 +30,7 @@ android { applicationIdSuffix = ".debug" proguardFiles (getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") resValue("string", "app_name", "Easy Launcher (Debug)") + resValue("string", "settings_backups_file", "autoBackup.debug.ini") } getByName("release") { @@ -37,6 +38,7 @@ android { isShrinkResources = true proguardFiles (getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") resValue("string", "app_name", "Easy Launcher") + resValue("string", "settings_backups_file", "autoBackup.ini") } } @@ -87,6 +89,7 @@ dependencies { implementation("androidx.work:work-runtime-ktx:2.9.0") implementation("androidx.recyclerview:recyclerview:1.3.2") implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("androidx.preference:preference-ktx:1.2.1") debugImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppExtensions.kt b/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppExtensions.kt index 447c1a0..69e4922 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppExtensions.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppExtensions.kt @@ -3,6 +3,7 @@ package com.github.droidworksstudio.launcher.helper import android.app.SearchManager import android.content.Context import android.content.Intent +import android.content.SharedPreferences import android.content.pm.LauncherApps import android.net.Uri import android.os.UserHandle @@ -10,7 +11,11 @@ import android.util.Log import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.EditText +import android.widget.Toast +import androidx.fragment.app.Fragment import com.github.droidworksstudio.launcher.Constants +import java.io.File +import java.io.IOException fun View.hideKeyboard() { this.clearFocus() @@ -74,6 +79,86 @@ fun Context.searchCustomSearchEngine(searchQuery: String? = null): Boolean { return true } +fun Context.backupSharedPreferences(backupFileName: String) { + val sharedPreferences: SharedPreferences = this.getSharedPreferences(Constants.PREFS_FILENAME, 0) + val allPrefs = sharedPreferences.all + val backupFile = File(filesDir, backupFileName) + + println("Backup SharedPreferences to: ${backupFile.absolutePath}") + + try { + backupFile.bufferedWriter().use { writer -> + for ((key, value) in allPrefs) { + if (value != null) { + val line = when (value) { + is Boolean -> "$key=${value}\n" + is Int -> "$key=${value}\n" + is Float -> "$key=${value}\n" + is Long -> "$key=${value}\n" + is String -> "$key=${value}\n" + is Set<*> -> "$key=${value.joinToString(",")}\n" + else -> null + } + if (line != null) { + writer.write(line) + println("Writing: $line") + } else { + println("Skipping unsupported type for key: $key") + } + } else { + println("Null value for key: $key") + } + } + } + println("Backup completed successfully.") + } catch (e: IOException) { + e.printStackTrace() + println("Failed to backup SharedPreferences: ${e.message}") + } +} + +fun Context.restoreSharedPreferences(backupFileName: String) { + val sharedPreferences: SharedPreferences = this.getSharedPreferences(Constants.PREFS_FILENAME, 0) + val editor = sharedPreferences.edit() + val backupFile = File(filesDir, backupFileName) + + println("Restoring SharedPreferences from: ${backupFile.absolutePath}") + + if (backupFile.exists()) { + try { + backupFile.forEachLine { line -> + val (key, value) = line.split("=", limit = 2) + when { + value.toBooleanStrictOrNull() != null -> editor.putBoolean(key, value.toBoolean()) + value.toIntOrNull() != null -> editor.putInt(key, value.toInt()) + value.toFloatOrNull() != null -> editor.putFloat(key, value.toFloat()) + value.toLongOrNull() != null -> editor.putLong(key, value.toLong()) + value.contains(",") -> editor.putStringSet(key, value.split(",").toSet()) + else -> editor.putString(key, value) + } + println("Restoring: $key=$value") + } + editor.apply() + println("Restore completed successfully.") + } catch (e: IOException) { + e.printStackTrace() + println("Failed to restore SharedPreferences: ${e.message}") + } + } else { + println("Backup file does not exist.") + } +} + +fun Fragment.restartApp() { + val packageManager = requireContext().packageManager + val intent = packageManager.getLaunchIntentForPackage(requireContext().packageName) + intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + if (intent != null) { + startActivity(intent) + } + requireActivity().finish() +} + fun Context.isPackageInstalled(packageName: String, userHandle: UserHandle = android.os.Process.myUserHandle()): Boolean { val launcher = getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps val activityInfo = launcher.getActivityList(packageName, userHandle) diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt b/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt index 5e7ec83..7e8be3b 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt @@ -267,7 +267,7 @@ class AppHelper @Inject constructor() { return dailyWordsArray[wordIndex] } - fun shareApp(context: Context){ + fun shareAppButton(context: Context){ val shareIntent = Intent(Intent.ACTION_SEND) shareIntent.type = "text/plain" shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Share Application") @@ -275,19 +275,27 @@ class AppHelper @Inject constructor() { context.startActivity(Intent.createChooser(shareIntent, "Share Application")) } - fun github(context: Context){ + fun githubButton(context: Context){ val uri = Uri.parse("https://github.com/DroidWorksStudio/EasyLauncher") val intent = Intent(Intent.ACTION_VIEW, uri) context.startActivity(intent) } - fun feedback(context: Context){ + fun feedbackButton(context: Context){ val emailIntent = Intent(Intent.ACTION_SENDTO) emailIntent.data = Uri.parse("mailto:droidworksstuido@063240.xyz") emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Easy Launcher") context.startActivity(Intent.createChooser(emailIntent, "Choose Mail Application")) } + fun backupSharedPreferences(context: Context) { + context.backupSharedPreferences(context.getString(R.string.settings_backups_file)) + } + + fun restoreSharedPreferences(context: Context) { + context.restoreSharedPreferences(context.getString(R.string.settings_backups_file)) + } + fun enableAppAsAccessibilityService(context: Context, accessibilityState: Boolean) { val state: String = if (accessibilityState) { context.getString(R.string.accessibility_settings_disable) diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt index 49c00e1..6f85f53 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFragment.kt @@ -7,6 +7,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.NavController @@ -15,6 +16,7 @@ import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.databinding.FragmentSettingsBinding import com.github.droidworksstudio.launcher.helper.AppHelper import com.github.droidworksstudio.launcher.helper.PreferenceHelper +import com.github.droidworksstudio.launcher.helper.restartApp import com.github.droidworksstudio.launcher.listener.ScrollEventListener import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AlignmentBottomSheetDialogFragment import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.ColorBottomSheetDialogFragment @@ -30,7 +32,6 @@ class SettingsFragment : Fragment(), ScrollEventListener { private var _binding: FragmentSettingsBinding? = null private val binding get() = _binding!! - //private val viewModel: AppViewModel by viewModels() private val preferenceViewModel: PreferenceViewModel by viewModels() @Inject @@ -127,15 +128,27 @@ class SettingsFragment : Fragment(), ScrollEventListener { } binding.shareView.setOnClickListener { - appHelper.shareApp(requireContext()) + appHelper.shareAppButton(requireContext()) } binding.githubView.setOnClickListener { - appHelper.github(requireContext()) + appHelper.githubButton(requireContext()) + } binding.feedbackView.setOnClickListener { - appHelper.feedback(requireContext()) + appHelper.feedbackButton(requireContext()) + } + + binding.backupView.setOnClickListener { + appHelper.backupSharedPreferences(requireContext()) + Toast.makeText(requireContext(), getString(R.string.settings_reload_app_backup), Toast.LENGTH_SHORT).show() + } + + binding.restoreView.setOnClickListener { + appHelper.restoreSharedPreferences(requireContext()) + Toast.makeText(requireContext(), getString(R.string.settings_reload_app_restore), Toast.LENGTH_SHORT).show() + restartApp() } } diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index f538ba4..073df8e 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -673,6 +673,49 @@ + + + + + + + + + + + + + + Time Style App Manage Gestures + Backups Others Show Status Bar @@ -75,6 +76,12 @@ Feedback Github + Backup Preferences + Restore Preferences + + Preferences backed up. + Preferences restored. Restarting. + Authentication Log in using your biometric credentials. Authentication Cancel