migrate to room db pt1/?

WARNING: does not compile as-is. tests are expected to fail.

[skip actions]

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/89/head
androidacy-user 3 years ago
parent 0265e3961d
commit 74e3a746b3

@ -19,8 +19,6 @@ plugins {
id("io.sentry.android.gradle") id("io.sentry.android.gradle")
} }
// apply realm-android
apply(plugin = "realm-android")
val hasSentryConfig = File(rootProject.projectDir, "sentry.properties").exists() val hasSentryConfig = File(rootProject.projectDir, "sentry.properties").exists()
android { android {
// functions to get git info: gitCommitHash, gitBranch, gitRemote // functions to get git info: gitCommitHash, gitBranch, gitRemote
@ -527,6 +525,9 @@ dependencies {
// yes // yes
implementation("com.github.fingerprintjs:fingerprint-android:2.0.0") implementation("com.github.fingerprintjs:fingerprint-android:2.0.0")
// encryption for room
implementation("net.zetetic:android-database-sqlcipher:4.5.4")
// room // room
implementation("androidx.room:room-runtime:2.5.1") implementation("androidx.room:room-runtime:2.5.1")

@ -195,6 +195,9 @@
-keepclassmembers class org.apache.commons.compress.archivers.zip.* { *; } -keepclassmembers class org.apache.commons.compress.archivers.zip.* { *; }
-keep,includedescriptorclasses class net.sqlcipher.** { *; }
-keep,includedescriptorclasses interface net.sqlcipher.** { *; }
# dontwarn # dontwarn
-dontwarn android.os.SystemProperties -dontwarn android.os.SystemProperties
-dontwarn android.view.ThreadedRenderer -dontwarn android.view.ThreadedRenderer

@ -28,6 +28,7 @@ import androidx.appcompat.widget.SearchView
import androidx.cardview.widget.CardView import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.room.Room
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import com.fox2code.foxcompat.app.FoxActivity import com.fox2code.foxcompat.app.FoxActivity
@ -54,11 +55,9 @@ import com.fox2code.mmm.utils.RuntimeUtils
import com.fox2code.mmm.utils.SyncManager import com.fox2code.mmm.utils.SyncManager
import com.fox2code.mmm.utils.io.net.Http.Companion.cleanDnsCache import com.fox2code.mmm.utils.io.net.Http.Companion.cleanDnsCache
import com.fox2code.mmm.utils.io.net.Http.Companion.hasWebView import com.fox2code.mmm.utils.io.net.Http.Companion.hasWebView
import com.fox2code.mmm.utils.realm.ReposList import com.fox2code.mmm.utils.room.ReposListDatabase
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.progressindicator.LinearProgressIndicator import com.google.android.material.progressindicator.LinearProgressIndicator
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matomo.sdk.extra.TrackHelper import org.matomo.sdk.extra.TrackHelper
import timber.log.Timber import timber.log.Timber
import java.sql.Timestamp import java.sql.Timestamp
@ -104,25 +103,24 @@ class MainActivity : FoxActivity(), OnRefreshListener, SearchView.OnQueryTextLis
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
TrackHelper.track().screen(this).with(MainApplication.INSTANCE!!.tracker) TrackHelper.track().screen(this).with(MainApplication.INSTANCE!!.tracker)
// track enabled repos // track enabled repos
val realmConfig = RealmConfiguration.Builder().name("ReposList.realm") val db = Room.databaseBuilder(
.encryptionKey(MainApplication.INSTANCE!!.key) applicationContext,
.directory(MainApplication.INSTANCE!!.getDataDirWithPath("realms")).schemaVersion(1) ReposListDatabase::class.java,
.allowQueriesOnUiThread(true).allowWritesOnUiThread(true).build() "reposlist.db"
val realm = Realm.getInstance(realmConfig) ).build()
val repoDao = db.reposListDao()
val repos = repoDao.getAll()
val enabledRepos = StringBuilder() val enabledRepos = StringBuilder()
realm.executeTransaction { r: Realm -> for (repo in repos) {
for (r2 in r.where( if (repo.enabled) {
ReposList::class.java enabledRepos.append(repo.url).append(", ")
).equalTo("enabled", true).findAll()) {
enabledRepos.append(r2.url).append(":").append(r2.name).append(",")
} }
} }
if (enabledRepos.isNotEmpty()) { if (enabledRepos.isNotEmpty()) {
enabledRepos.setLength(enabledRepos.length - 1) enabledRepos.delete(enabledRepos.length - 2, enabledRepos.length)
TrackHelper.track().event("Enabled Repos", enabledRepos.toString())
.with(MainApplication.INSTANCE!!.tracker)
} }
TrackHelper.track().event("enabled_repos", enabledRepos.toString())
.with(MainApplication.INSTANCE!!.tracker)
realm.close()
// hide this behind a buildconfig flag for now, but crash the app if it's not an official build and not debug // hide this behind a buildconfig flag for now, but crash the app if it's not an official build and not debug
if (BuildConfig.ENABLE_PROTECTION && !MainApplication.o && !BuildConfig.DEBUG) { if (BuildConfig.ENABLE_PROTECTION && !MainApplication.o && !BuildConfig.DEBUG) {
throw RuntimeException("This is not an official build of AMM") throw RuntimeException("This is not an official build of AMM")

@ -18,10 +18,13 @@ import android.webkit.CookieManager
import android.widget.CompoundButton import android.widget.CompoundButton
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.room.Room
import com.fox2code.foxcompat.app.FoxActivity import com.fox2code.foxcompat.app.FoxActivity
import com.fox2code.mmm.databinding.ActivitySetupBinding import com.fox2code.mmm.databinding.ActivitySetupBinding
import com.fox2code.mmm.utils.IntentHelper import com.fox2code.mmm.utils.IntentHelper
import com.fox2code.mmm.utils.realm.ReposList import com.fox2code.mmm.utils.realm.ReposList
import com.fox2code.mmm.utils.room.ModuleListCacheDatabase
import com.fox2code.mmm.utils.room.ReposListDatabase
import com.fox2code.rosettax.LanguageActivity import com.fox2code.rosettax.LanguageActivity
import com.fox2code.rosettax.LanguageSwitcher import com.fox2code.rosettax.LanguageSwitcher
import com.google.android.material.bottomnavigation.BottomNavigationItemView import com.google.android.material.bottomnavigation.BottomNavigationItemView
@ -254,7 +257,7 @@ class SetupActivity : FoxActivity(), LanguageActivity {
r.close() r.close()
Timber.d("Realm transaction committed") Timber.d("Realm transaction committed")
} }
editor.putString("last_shown_setup", "v2") editor.putString("last_shown_setup", "v3")
// Commit the changes // Commit the changes
editor.commit() editor.commit()
// sleep to allow the realm transaction to finish // sleep to allow the realm transaction to finish
@ -347,7 +350,18 @@ class SetupActivity : FoxActivity(), LanguageActivity {
// creates the room database // creates the room database
private fun createDatabases() { private fun createDatabases() {
val startTime = System.currentTimeMillis()
val appContext = MainApplication.INSTANCE!!.applicationContext val appContext = MainApplication.INSTANCE!!.applicationContext
Room.databaseBuilder(appContext, ReposListDatabase::class.java, "reposlist.db")
.createFromAsset("assets/reposlist.db")
.fallbackToDestructiveMigration()
.build()
// same for modulelistcache
Room.databaseBuilder(appContext, ModuleListCacheDatabase::class.java, "modulelistcache.db")
.createFromAsset("assets/modulelistcache.db")
.fallbackToDestructiveMigration()
.build()
Timber.d("Databases created in %s ms", System.currentTimeMillis() - startTime)
} }
private fun createFiles() { private fun createFiles() {

@ -374,7 +374,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
fun onMainActivityCreate(context: Context) { fun onMainActivityCreate(context: Context) {
// Refuse to run if first_launch pref is not false // Refuse to run if first_launch pref is not false
if (MainApplication.getSharedPreferences("mmm")!! if (MainApplication.getSharedPreferences("mmm")!!
.getString("last_shown_setup", null) != "v2" .getString("last_shown_setup", null) != "v3"
) return ) return
// create notification channel group // create notification channel group
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

@ -7,25 +7,24 @@
package com.fox2code.mmm.manager package com.fox2code.mmm.manager
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.room.Room
import com.fox2code.mmm.BuildConfig import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.installer.InstallerInitializer.Companion.peekModulesPath import com.fox2code.mmm.installer.InstallerInitializer.Companion.peekModulesPath
import com.fox2code.mmm.utils.SyncManager import com.fox2code.mmm.utils.SyncManager
import com.fox2code.mmm.utils.io.PropUtils import com.fox2code.mmm.utils.io.PropUtils
import com.fox2code.mmm.utils.realm.ModuleListCache import com.fox2code.mmm.utils.room.ModuleListCache
import com.fox2code.mmm.utils.room.ModuleListCacheDao
import com.fox2code.mmm.utils.room.ModuleListCacheDatabase
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile
import com.topjohnwu.superuser.io.SuFileInputStream import com.topjohnwu.superuser.io.SuFileInputStream
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matomo.sdk.extra.TrackHelper import org.matomo.sdk.extra.TrackHelper
import timber.log.Timber import timber.log.Timber
import java.io.BufferedReader import java.io.BufferedReader
import java.io.File
import java.io.IOException import java.io.IOException
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.util.Objects
class ModuleManager private constructor() : SyncManager() { class ModuleManager private constructor() : SyncManager() {
private val moduleInfos: HashMap<String, LocalModuleInfo> = HashMap() private val moduleInfos: HashMap<String, LocalModuleInfo> = HashMap()
@ -33,9 +32,9 @@ class ModuleManager private constructor() : SyncManager() {
private var updatableModuleCount = 0 private var updatableModuleCount = 0
override fun scanInternal(updateListener: UpdateListener) { override fun scanInternal(updateListener: UpdateListener) {
// if last_shown_setup is not "v2", then refuse to continue // if last_shown_setup is not "v3", then refuse to continue
if (MainApplication.getSharedPreferences("mmm")!! if (MainApplication.getSharedPreferences("mmm")!!
.getString("last_shown_setup", "") != "v2" .getString("last_shown_setup", "") != "v3"
) { ) {
return return
} }
@ -65,60 +64,36 @@ class ModuleManager private constructor() : SyncManager() {
for (module in modules) { for (module in modules) {
if (!SuFile("/data/adb/modules/$module").isDirectory) continue // Ignore non directory files inside modules folder if (!SuFile("/data/adb/modules/$module").isDirectory) continue // Ignore non directory files inside modules folder
var moduleInfo = moduleInfos[module] var moduleInfo = moduleInfos[module]
// next, merge the module info with a record from ModuleListCache if it exists // next, merge the module info with a record from ModuleListCache room db if it exists
var realmConfiguration: RealmConfiguration? // initialize modulelistcache db
// get all dirs under the realms/repos/ dir under app's data dir // DO NOT USE REALM ANYMORE
val cacheRoot = val db = Room.databaseBuilder(
File(MainApplication.INSTANCE!!.getDataDirWithPath("realms/repos/").toURI()) MainApplication.INSTANCE!!,
var moduleListCache: ModuleListCache? ModuleListCacheDatabase::class.java,
for (dir in Objects.requireNonNull<Array<File>>(cacheRoot.listFiles())) { "ModuleListCache"
if (dir.isDirectory) { ).build()
// if the dir name matches the module name, use it as the cache dir // get module info from cache
val tempCacheRoot = File(dir.toString()) val moduleListCacheDao: ModuleListCacheDao = db.moduleListCacheDao()
Timber.d("Looking for cache in %s", tempCacheRoot) Timber.d("Found cache for %s", module)
realmConfiguration = // get module info from cache
RealmConfiguration.Builder().name("ModuleListCache.realm")
.encryptionKey(MainApplication.INSTANCE!!.key).schemaVersion(1)
.deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true)
.allowQueriesOnUiThread(true).directory(tempCacheRoot).build()
val realm = Realm.getInstance(realmConfiguration!!)
Timber.d(
"Looking for cache for %s out of %d", module, realm.where(
ModuleListCache::class.java
).count()
)
moduleListCache =
realm.where(ModuleListCache::class.java).equalTo("codename", module)
.findFirst()
Timber.d("Found cache for %s", module)
// get module info from cache
if (moduleInfo == null) {
moduleInfo = LocalModuleInfo(module)
}
if (moduleListCache != null) {
moduleInfo.name =
if (moduleListCache.name != "") moduleListCache.name else module
moduleInfo.description =
if (moduleListCache.description != "") moduleListCache.description else moduleInfo.description
moduleInfo.author =
if (moduleListCache.author != "") moduleListCache.author else moduleInfo.author
moduleInfo.safe = moduleListCache.isSafe == true
moduleInfo.support =
if (moduleListCache.support != "") moduleListCache.support else null
moduleInfo.donate =
if (moduleListCache.donate != "") moduleListCache.donate else null
moduleInfo.flags = moduleInfo.flags or FLAG_MM_REMOTE_MODULE
moduleInfos[module] = moduleInfo
}
realm.close()
break
}
}
if (moduleInfo == null) { if (moduleInfo == null) {
moduleInfo = LocalModuleInfo(module) moduleInfo = LocalModuleInfo(module)
}
if (moduleListCacheDao.exists(module)) {
val moduleListCache: ModuleListCache = moduleListCacheDao.getByCodename(module)
moduleInfo.name =
if (moduleListCache.name != "") moduleListCache.name else module
moduleInfo.description =
if (moduleListCache.description != "") moduleListCache.description else moduleInfo.description
moduleInfo.author =
if (moduleListCache.author != "") moduleListCache.author else moduleInfo.author
moduleInfo.safe = moduleListCache.safe == true
moduleInfo.support =
if (moduleListCache.support != "") moduleListCache.support else null
moduleInfo.donate =
if (moduleListCache.donate != "") moduleListCache.donate else null
moduleInfo.flags = moduleInfo.flags or FLAG_MM_REMOTE_MODULE
moduleInfos[module] = moduleInfo moduleInfos[module] = moduleInfo
// This should not really happen, but let's handles theses cases anyway
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_UPDATING_ONLY
} }
moduleInfo.flags = moduleInfo.flags and FLAGS_RESET_UPDATE.inv() moduleInfo.flags = moduleInfo.flags and FLAGS_RESET_UPDATE.inv()
if (SuFile("/data/adb/modules/$module/disable").exists()) { if (SuFile("/data/adb/modules/$module/disable").exists()) {
@ -131,8 +106,7 @@ class ModuleManager private constructor() : SyncManager() {
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_UNINSTALLING moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_UNINSTALLING
} }
if (firstScan && !needFallback && SuFile( if (firstScan && !needFallback && SuFile(
modulesPath, modulesPath, module
module
).exists() || bootPrefs.getBoolean("module_" + moduleInfo.id + "_active", false) ).exists() || bootPrefs.getBoolean("module_" + moduleInfo.id + "_active", false)
) { ) {
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_ACTIVE moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_ACTIVE
@ -152,9 +126,7 @@ class ModuleManager private constructor() : SyncManager() {
} }
try { try {
PropUtils.readProperties( PropUtils.readProperties(
moduleInfo, moduleInfo, "/data/adb/modules/$module/module.prop", true
"/data/adb/modules/$module/module.prop",
true
) )
} catch (e: Exception) { } catch (e: Exception) {
if (BuildConfig.DEBUG) Timber.d(e) if (BuildConfig.DEBUG) Timber.d(e)
@ -186,9 +158,7 @@ class ModuleManager private constructor() : SyncManager() {
moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_UPDATING moduleInfo.flags = moduleInfo.flags or ModuleInfo.FLAG_MODULE_UPDATING
try { try {
PropUtils.readProperties( PropUtils.readProperties(
moduleInfo, moduleInfo, "/data/adb/modules_update/$module/module.prop", true
"/data/adb/modules_update/$module/module.prop",
true
) )
} catch (e: Exception) { } catch (e: Exception) {
if (BuildConfig.DEBUG) Timber.d(e) if (BuildConfig.DEBUG) Timber.d(e)

@ -3,23 +3,21 @@
*/ */
package com.fox2code.mmm.repo package com.fox2code.mmm.repo
import androidx.room.Room
import com.fox2code.mmm.MainApplication import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.Companion.INSTANCE import com.fox2code.mmm.MainApplication.Companion.INSTANCE
import com.fox2code.mmm.MainApplication.Companion.getSharedPreferences import com.fox2code.mmm.MainApplication.Companion.getSharedPreferences
import com.fox2code.mmm.utils.io.Hashes.Companion.hashSha256 import com.fox2code.mmm.utils.io.Hashes.Companion.hashSha256
import com.fox2code.mmm.utils.io.PropUtils.Companion.isNullString import com.fox2code.mmm.utils.io.PropUtils.Companion.isNullString
import com.fox2code.mmm.utils.io.net.Http.Companion.doHttpGet import com.fox2code.mmm.utils.io.net.Http.Companion.doHttpGet
import com.fox2code.mmm.utils.realm.ReposList import com.fox2code.mmm.utils.room.ReposListDatabase
import io.realm.Realm
import io.realm.RealmConfiguration
import org.json.JSONObject import org.json.JSONObject
import timber.log.Timber import timber.log.Timber
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@Suppress("UNUSED_PARAMETER", "MemberVisibilityCanBePrivate") @Suppress("UNUSED_PARAMETER", "MemberVisibilityCanBePrivate")
class CustomRepoManager internal constructor( class CustomRepoManager internal constructor(
mainApplication: MainApplication?, mainApplication: MainApplication?, private val repoManager: RepoManager
private val repoManager: RepoManager
) { ) {
private val customRepos: Array<String?> = arrayOfNulls(MAX_CUSTOM_REPOS) private val customRepos: Array<String?> = arrayOfNulls(MAX_CUSTOM_REPOS)
@ -31,34 +29,24 @@ class CustomRepoManager internal constructor(
init { init {
repoCount = 0 repoCount = 0
// refuse to load if setup is not complete // refuse to load if setup is not complete
if (getSharedPreferences("mmm")!!.getString("last_shown_setup", "") != "") { if (getSharedPreferences("mmm")!!.getString("last_shown_setup", "") == "v3") {
val realmConfiguration =
RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(
INSTANCE!!.key
).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(
INSTANCE!!.getDataDirWithPath("realms")
).schemaVersion(1).build()
val realm = Realm.getInstance(realmConfiguration)
if (realm.isInTransaction) {
realm.commitTransaction()
}
val i = 0 val i = 0
val lastFilled = intArrayOf(0) val lastFilled = intArrayOf(0)
realm.executeTransaction { realm1: Realm -> // now the same as above but for room database
// find all repos that are not built-in val applicationContext = mainApplication!!.applicationContext
for (reposList in realm1.where(ReposList::class.java) val db = Room.databaseBuilder(
.notEqualTo("id", "androidacy_repo").and().notEqualTo("id", "magisk_alt_repo") applicationContext, ReposListDatabase::class.java, "reposlist.db"
.and() ).build()
.notEqualTo("id", "magisk_official_repo").findAll()) { val reposListDao = db.reposListDao()
val repo = reposList.url val reposListList = reposListDao.getAll()
if (!isNullString(repo) && !RepoManager.isBuiltInRepo(repo)) { for (reposList in reposListList) {
lastFilled[0] = i val repo = reposList.url
val index = if (AUTO_RECOMPILE) repoCount else i if (!isNullString(repo) && !RepoManager.isBuiltInRepo(repo)) {
customRepos[index] = repo lastFilled[0] = i
repoCount++ val index = if (AUTO_RECOMPILE) repoCount else i
(repoManager.addOrGet(repo) as CustomRepoData).override = customRepos[index] = repo
"custom_repo_$index" repoCount++
} (repoManager.addOrGet(repo) as CustomRepoData).override = "custom_repo_$index"
} }
} }
} }
@ -119,29 +107,13 @@ class CustomRepoManager internal constructor(
null null
} }
val id = "repo_" + hashSha256(repo.toByteArray(StandardCharsets.UTF_8)) val id = "repo_" + hashSha256(repo.toByteArray(StandardCharsets.UTF_8))
val realmConfiguration = RealmConfiguration.Builder().name("ReposList.realm").encryptionKey( // now the same as above but for room database
INSTANCE!!.key val applicationContext = INSTANCE!!.applicationContext
).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory( val db = Room.databaseBuilder(
INSTANCE!!.getDataDirWithPath("realms") applicationContext, ReposListDatabase::class.java, "reposlist.db"
).schemaVersion(1).build() ).build()
val realm = Realm.getInstance(realmConfiguration) val reposListDao = db.reposListDao()
realm.executeTransaction { realm1: Realm -> reposListDao.insert(id, repo, true, donate, support, submitModule, 0, name, website)
// find the matching entry for repo_0, repo_1, etc.
var reposList =
realm1.where(ReposList::class.java).equalTo("id", id).findFirst()
if (reposList == null) {
reposList = realm1.createObject(ReposList::class.java, id)
}
reposList!!.url = repo
reposList.name = name
reposList.website = website
reposList.support = support
reposList.donate = donate
reposList.submitModule = submitModule
reposList.isEnabled = true
// save the object
realm1.copyToRealmOrUpdate(reposList)
}
repoCount++ repoCount++
dirty = true dirty = true
val customRepoData = repoManager.addOrGet(repo) as CustomRepoData val customRepoData = repoManager.addOrGet(repo) as CustomRepoData
@ -155,7 +127,6 @@ class CustomRepoManager internal constructor(
// Set the enabled state to true // Set the enabled state to true
customRepoData.isEnabled = true customRepoData.isEnabled = true
customRepoData.updateEnabledState() customRepoData.updateEnabledState()
realm.close()
return customRepoData return customRepoData
} }

@ -56,7 +56,7 @@ class RepoManager private constructor(mainApplication: MainApplication) : SyncMa
repoData = LinkedHashMap() repoData = LinkedHashMap()
modules = HashMap() modules = HashMap()
// refuse to load if setup is not complete // refuse to load if setup is not complete
if (getSharedPreferences("mmm")!!.getString("last_shown_setup", "") != "") { if (getSharedPreferences("mmm")!!.getString("last_shown_setup", "") == "v3") {
// We do not have repo list config yet. // We do not have repo list config yet.
androidacyRepoData = addAndroidacyRepoData() androidacyRepoData = addAndroidacyRepoData()
val altRepo = addRepoData(MAGISK_ALT_REPO, "Magisk Modules Alt Repo") val altRepo = addRepoData(MAGISK_ALT_REPO, "Magisk Modules Alt Repo")
@ -82,8 +82,8 @@ class RepoManager private constructor(mainApplication: MainApplication) : SyncMa
} }
private fun populateDefaultCache(repoData: RepoData?) { private fun populateDefaultCache(repoData: RepoData?) {
// if last_shown_setup is not "v2", them=n refuse to continue // if last_shown_setup is not "v3", them=n refuse to continue
if (getSharedPreferences("mmm")!!.getString("last_shown_setup", "") != "v2") { if (getSharedPreferences("mmm")!!.getString("last_shown_setup", "") != "v3") {
return return
} }
// make sure repodata is not null // make sure repodata is not null

@ -154,7 +154,7 @@ class RuntimeUtils {
if (BuildConfig.DEBUG) Timber.i("Checking if we need to run setup") if (BuildConfig.DEBUG) Timber.i("Checking if we need to run setup")
// Check if context is the first launch using prefs and if doSetupRestarting was passed in the intent // Check if context is the first launch using prefs and if doSetupRestarting was passed in the intent
val prefs = MainApplication.getSharedPreferences("mmm")!! val prefs = MainApplication.getSharedPreferences("mmm")!!
var firstLaunch = prefs.getString("last_shown_setup", null) != "v2" var firstLaunch = prefs.getString("last_shown_setup", null) != "v3"
// First launch // First launch
// context is intentionally separate from the above if statement, because it needs to be checked even if the first launch check is true due to some weird edge cases // context is intentionally separate from the above if statement, because it needs to be checked even if the first launch check is true due to some weird edge cases
if (activity.intent.getBooleanExtra("doSetupRestarting", false)) { if (activity.intent.getBooleanExtra("doSetupRestarting", false)) {

@ -1,317 +0,0 @@
/*
* Copyright (c) 2023 to present Androidacy and contributors. Names, logos, icons, and the Androidacy name are all trademarks of Androidacy and may not be used without license. See LICENSE for more information.
*/
package com.fox2code.mmm.utils.realm;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import io.realm.Realm;
import io.realm.RealmObject;
import io.realm.RealmResults;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required;
import timber.log.Timber;
@SuppressWarnings("unused")
public class ModuleListCache extends RealmObject {
// for compatibility, only id is required
@PrimaryKey
@Required
private String codename;
private String name;
private String version;
private int versionCode;
private String author;
private String description;
private int minApi;
private int maxApi;
private int minMagisk;
private boolean needRamdisk;
private String support;
private String donate;
private String config;
private boolean changeBoot;
private boolean mmtReborn;
private String repoId;
private boolean installed;
private int installedVersionCode;
private int lastUpdate;
// androidacy specific, may be added by other repos
private boolean safe;
private int stats;
public ModuleListCache(String codename, String name, String version, int versionCode, String author, String description, int minApi, int maxApi, int minMagisk, boolean needRamdisk, String support, String donate, String config, boolean changeBoot, boolean mmtReborn, String repoId, boolean installed, int installedVersionCode, int lastUpdate, int stats) {
this.codename = codename;
this.name = name;
this.version = version;
this.versionCode = versionCode;
this.author = author;
this.description = description;
this.minApi = minApi;
this.maxApi = maxApi;
this.minMagisk = minMagisk;
this.needRamdisk = needRamdisk;
this.support = support;
this.donate = donate;
this.config = config;
this.changeBoot = changeBoot;
this.mmtReborn = mmtReborn;
this.repoId = repoId;
this.installed = installed;
this.installedVersionCode = installedVersionCode;
this.lastUpdate = lastUpdate;
this.safe = false;
this.stats = stats;
}
public ModuleListCache() {
}
// get all modules from a repo as a json object
public static JSONObject getRepoModulesAsJson(String repoId) {
Realm realm = Realm.getDefaultInstance();
RealmResults<ModuleListCache> modules = realm.where(ModuleListCache.class).equalTo("repoId", repoId).findAll();
JSONObject jsonObject = new JSONObject();
for (ModuleListCache module : modules) {
try {
jsonObject.put(module.getCodename(), module.toJson());
} catch (
JSONException e) {
Timber.e(e);
}
}
realm.close();
return jsonObject;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getVersionCode() {
return versionCode;
}
public void setVersionCode(int versionCode) {
this.versionCode = versionCode;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getSupport() {
return support;
}
public void setSupport(String support) {
this.support = support;
}
public String getDonate() {
return donate;
}
public void setDonate(String donate) {
this.donate = donate;
}
public String getConfig() {
return config;
}
public void setConfig(String config) {
this.config = config;
}
public boolean isChangeBoot() {
return changeBoot;
}
public void setChangeBoot(boolean changeBoot) {
this.changeBoot = changeBoot;
}
public boolean isMmtReborn() {
return mmtReborn;
}
public void setMmtReborn(boolean mmtReborn) {
this.mmtReborn = mmtReborn;
}
public String getRepoId() {
return repoId;
}
public void setRepoId(String repoId) {
this.repoId = repoId;
}
public boolean isInstalled() {
return installed;
}
public void setInstalled(boolean installed) {
this.installed = installed;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public int getMinApi() {
return minApi;
}
public void setMinApi(int minApi) {
this.minApi = minApi;
}
public int getMaxApi() {
return maxApi;
}
public void setMaxApi(int maxApi) {
this.maxApi = maxApi;
}
public int getMinMagisk() {
return minMagisk;
}
public void setMinMagisk(int minMagisk) {
this.minMagisk = minMagisk;
}
public boolean isNeedRamdisk() {
return needRamdisk;
}
public void setNeedRamdisk(boolean needRamdisk) {
this.needRamdisk = needRamdisk;
}
public int getInstalledVersionCode() {
return installedVersionCode;
}
public void setInstalledVersionCode(int installedVersionCode) {
this.installedVersionCode = installedVersionCode;
}
public String getCodename() {
return codename;
}
public void setCodename(String codename) {
this.codename = codename;
}
public int getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(int lastUpdate) {
this.lastUpdate = lastUpdate;
}
public boolean isSafe() {
return safe;
}
public void setSafe(boolean safe) {
this.safe = safe;
}
public int getStats() {
return stats;
}
public void setStats(int stats) {
this.stats = stats;
}
private JSONObject toJson() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("name", name);
jsonObject.put("version", version);
jsonObject.put("versionCode", versionCode);
jsonObject.put("author", author);
jsonObject.put("description", description);
jsonObject.put("minApi", minApi);
jsonObject.put("maxApi", maxApi);
jsonObject.put("minMagisk", minMagisk);
jsonObject.put("needRamdisk", needRamdisk);
jsonObject.put("support", support);
jsonObject.put("donate", donate);
jsonObject.put("config", config);
jsonObject.put("changeBoot", changeBoot);
jsonObject.put("mmtReborn", mmtReborn);
jsonObject.put("repoId", repoId);
jsonObject.put("installed", installed);
jsonObject.put("installedVersionCode", installedVersionCode);
jsonObject.put("lastUpdate", lastUpdate);
jsonObject.put("safe", safe);
jsonObject.put("stats", stats);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
public RealmResults<ModuleListCache> getModules() {
// return all modules matching the repo id
Realm realm = Realm.getDefaultInstance();
RealmResults<ModuleListCache> modules = realm.where(ModuleListCache.class).equalTo("repoId", repoId).findAll();
realm.close();
return modules;
}
// same as above but returns a json object
public JSONObject getModulesAsJson(String repoId) {
Realm realm = Realm.getDefaultInstance();
RealmResults<ModuleListCache> modules = realm.where(ModuleListCache.class).equalTo("repoId", repoId).findAll();
JSONObject jsonObject = new JSONObject();
// everything goes under top level "modules" key
try {
jsonObject.put("modules", new JSONArray());
} catch (JSONException ignored) {
// we should never get here
}
for (ModuleListCache module : modules) {
try {
jsonObject.getJSONArray("modules").put(module.toJson());
} catch (
JSONException e) {
Timber.e(e);
}
}
realm.close();
return jsonObject;
}
}

@ -1,122 +0,0 @@
/*
* Copyright (c) 2023 to present Androidacy and contributors. Names, logos, icons, and the Androidacy name are all trademarks of Androidacy and may not be used without license. See LICENSE for more information.
*/
package com.fox2code.mmm.utils.realm;
import io.realm.Realm;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.Required;
@SuppressWarnings("unused")
public class ReposList extends RealmObject {
// Each repo is identified by its id, has a url field, and an enabled field
// there's also an optional donate and support field
@Required
@PrimaryKey
private String id;
@Required
private String url;
private boolean enabled;
private String donate;
private String support;
private String submitModule;
private int lastUpdate;
private String website;
private String name;
public ReposList(String id, String url, boolean enabled, String donate, String support) {
this.id = id;
this.url = url;
this.enabled = enabled;
this.donate = donate;
this.support = support;
this.submitModule = null;
this.lastUpdate = 0;
}
public ReposList() {
}
// get metadata for a repo
public static ReposList getRepo(String id) {
Realm realm = Realm.getDefaultInstance();
ReposList repo = realm.where(ReposList.class).equalTo("id", id).findFirst();
realm.close();
return repo;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDonate() {
return donate;
}
public void setDonate(String donate) {
this.donate = donate;
}
public String getSupport() {
return support;
}
public void setSupport(String support) {
this.support = support;
}
public String getSubmitModule() {
return submitModule;
}
public void setSubmitModule(String submitModule) {
this.submitModule = submitModule;
}
public int getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(int lastUpdate) {
this.lastUpdate = lastUpdate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWebsite() {
return website;
}
public void setWebsite(String website) {
this.website = website;
}
}

@ -24,7 +24,9 @@ class ModuleListCache (
var changeBoot: Boolean, var changeBoot: Boolean,
var mmtReborn: Boolean, var mmtReborn: Boolean,
var repoId: String, var repoId: String,
var lastUpdate: Long var lastUpdate: Long,
val name: String,
var safe: Boolean
) { ) {
// functions: // functions:
// getAll(): List<ModuleListCache> // getAll(): List<ModuleListCache>

@ -5,11 +5,13 @@
package com.fox2code.mmm.utils.room package com.fox2code.mmm.utils.room
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
// contains // contains
// codename (string, primary), version (string), versionCode (int), author (string), description (string), minApi (int), maxApi (int), minMagisk (int), needRamdisk (boolean), support (string), donate (string), config (string), changeBoot (bool), mmtReborn (bool), repoId (string), lastUpdate (bigint) // codename (string, primary), version (string), versionCode (int), author (string), description (string), minApi (int), maxApi (int), minMagisk (int), needRamdisk (boolean), support (string), donate (string), config (string), changeBoot (bool), mmtReborn (bool), repoId (string), lastUpdate (bigint), safe (bool)
@Suppress("unused") @Suppress("unused")
@Dao @Dao
interface ModuleListCacheDao { interface ModuleListCacheDao {
@ -66,8 +68,8 @@ interface ModuleListCacheDao {
@Query("SELECT * FROM modulelistcache WHERE codename = :codename") @Query("SELECT * FROM modulelistcache WHERE codename = :codename")
fun getByCodename(codename: String): ModuleListCache fun getByCodename(codename: String): ModuleListCache
@Query("INSERT INTO modulelistcache VALUES (:codename, :version, :versionCode, :author, :description, :minApi, :maxApi, :minMagisk, :needRamdisk, :support, :donate, :config, :changeBoot, :mmtReborn, :repoId, :lastUpdate)") @Insert(entity = ModuleListCache::class, onConflict = OnConflictStrategy.REPLACE)
fun insert(codename: String, version: String, versionCode: Int, author: String, description: String, minApi: Int, maxApi: Int, minMagisk: Int, needRamdisk: Boolean, support: String, donate: String, config: String, changeBoot: Boolean, mmtReborn: Boolean, repoId: String, lastUpdate: Long) fun insert(codename: String, version: String, versionCode: Int, author: String, description: String, minApi: Int, maxApi: Int, minMagisk: Int, needRamdisk: Boolean, support: String, donate: String, config: String, changeBoot: Boolean, mmtReborn: Boolean, repoId: String, lastUpdate: Long, safe: Boolean, name: String)
@Query("UPDATE modulelistcache SET version = :version WHERE codename = :codename") @Query("UPDATE modulelistcache SET version = :version WHERE codename = :codename")
fun setVersion(codename: String, version: String) fun setVersion(codename: String, version: String)
@ -114,6 +116,12 @@ interface ModuleListCacheDao {
@Query("UPDATE modulelistcache SET lastUpdate = :lastUpdate WHERE codename = :codename") @Query("UPDATE modulelistcache SET lastUpdate = :lastUpdate WHERE codename = :codename")
fun setLastUpdate(codename: String, lastUpdate: Long) fun setLastUpdate(codename: String, lastUpdate: Long)
@Query("UPDATE modulelistcache SET safe = :safe WHERE codename = :codename")
fun setSafe(codename: String, safe: Boolean)
@Query("UPDATE modulelistcache SET name = :name WHERE codename = :codename")
fun setName(codename: String, name: String)
@Query("DELETE FROM modulelistcache WHERE codename = :codename") @Query("DELETE FROM modulelistcache WHERE codename = :codename")
fun delete(codename: String) fun delete(codename: String)
@ -168,6 +176,16 @@ interface ModuleListCacheDao {
@Query("SELECT lastUpdate FROM modulelistcache WHERE codename = :codename") @Query("SELECT lastUpdate FROM modulelistcache WHERE codename = :codename")
fun getLastUpdate(codename: String): Long fun getLastUpdate(codename: String): Long
@Query("SELECT safe FROM modulelistcache WHERE codename = :codename")
fun getSafe(codename: String): Boolean
@Query("SELECT name FROM modulelistcache WHERE codename = :codename")
fun getName(codename: String): String
@Query("SELECT * FROM modulelistcache WHERE codename = :codename") @Query("SELECT * FROM modulelistcache WHERE codename = :codename")
fun get(codename: String): ModuleListCache fun get(codename: String): ModuleListCache
// exists
@Query("SELECT EXISTS(SELECT * FROM modulelistcache WHERE codename = :codename)")
fun exists(codename: String): Boolean
} }

@ -5,9 +5,10 @@
package com.fox2code.mmm.utils.room package com.fox2code.mmm.utils.room
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase
@Suppress("unused") @Suppress("unused")
@Database(entities = [ModuleListCache::class], version = 1) @Database(entities = [ModuleListCache::class], version = 1)
abstract class ModuleListCacheDatabase { abstract class ModuleListCacheDatabase : RoomDatabase() {
abstract fun moduleListCacheDao(): ModuleListCacheDao abstract fun moduleListCacheDao(): ModuleListCacheDao
} }

@ -12,10 +12,10 @@ data class ReposList(
@PrimaryKey var id: String, @PrimaryKey var id: String,
var url: String, var url: String,
var enabled: Boolean, var enabled: Boolean,
var donate: String, var donate: String?,
var support: String, var support: String?,
var submitModule: String, var submitModule: String?,
var lastUpdate: Long, var lastUpdate: Int,
var name: String, var name: String,
var website: String var website: String?
) )

@ -27,7 +27,7 @@ interface ReposListDao {
fun getById(id: String): ReposList fun getById(id: String): ReposList
@Query("INSERT INTO ReposList VALUES (:id, :url, :enabled, :donate, :support, :submitModule, :lastUpdate, :name, :website)") @Query("INSERT INTO ReposList VALUES (:id, :url, :enabled, :donate, :support, :submitModule, :lastUpdate, :name, :website)")
fun insert(id: String, url: String, enabled: Boolean, donate: String, support: String, submitModule: String, lastUpdate: Long, name: String, website: String) fun insert(id: String, url: String, enabled: Boolean, donate: String?, support: String?, submitModule: String?, lastUpdate: Long, name: String, website: String?)
@Query("UPDATE ReposList SET url = :url, enabled = :enabled, donate = :donate, support = :support, submitModule = :submitModule, lastUpdate = :lastUpdate, name = :name, website = :website WHERE id = :id") @Query("UPDATE ReposList SET url = :url, enabled = :enabled, donate = :donate, support = :support, submitModule = :submitModule, lastUpdate = :lastUpdate, name = :name, website = :website WHERE id = :id")
fun update(id: String, url: String, enabled: Boolean, donate: String, support: String, submitModule: String, lastUpdate: Long, name: String, website: String) fun update(id: String, url: String, enabled: Boolean, donate: String, support: String, submitModule: String, lastUpdate: Long, name: String, website: String)

@ -77,7 +77,7 @@ object SentryMain {
} }
// If first_launch pref is not false, refuse to initialize Sentry // If first_launch pref is not false, refuse to initialize Sentry
val sharedPreferences = MainApplication.getSharedPreferences("mmm")!! val sharedPreferences = MainApplication.getSharedPreferences("mmm")!!
if (sharedPreferences.getString("last_shown_setup", null) != "v2") { if (sharedPreferences.getString("last_shown_setup", null) != "v3") {
return return
} }
isSentryEnabled = sharedPreferences.getBoolean("pref_crash_reporting_enabled", false) isSentryEnabled = sharedPreferences.getBoolean("pref_crash_reporting_enabled", false)

@ -24,7 +24,6 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
classpath("io.realm:realm-gradle-plugin:10.16.0")
classpath("io.sentry:sentry-android-gradle-plugin:3.7.0") classpath("io.sentry:sentry-android-gradle-plugin:3.7.0")
classpath("org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin:2.7.1") classpath("org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin:2.7.1")
} }

Loading…
Cancel
Save