diff --git a/app/src/main/assets/modulelistcache.db b/app/src/main/assets/modulelistcache.db index 1338adb..d638fcd 100644 Binary files a/app/src/main/assets/modulelistcache.db and b/app/src/main/assets/modulelistcache.db differ diff --git a/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt index 890d305..e550098 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt @@ -22,7 +22,6 @@ import androidx.room.Room import com.fox2code.foxcompat.app.FoxActivity import com.fox2code.mmm.databinding.ActivitySetupBinding import com.fox2code.mmm.utils.IntentHelper -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 @@ -33,8 +32,6 @@ import com.google.android.material.checkbox.MaterialCheckBox import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.materialswitch.MaterialSwitch import com.topjohnwu.superuser.internal.UiThreadHandler -import io.realm.Realm -import io.realm.RealmConfiguration import org.apache.commons.io.FileUtils import timber.log.Timber import java.io.File @@ -43,7 +40,6 @@ import java.util.Objects class SetupActivity : FoxActivity(), LanguageActivity { private var cachedTheme = 0 - private var realmDatabasesCreated = false @SuppressLint("ApplySharedPref", "RestrictedApi") override fun onCreate(savedInstanceState: Bundle?) { @@ -227,36 +223,19 @@ class SetupActivity : FoxActivity(), LanguageActivity { (Objects.requireNonNull(view.findViewById(R.id.setup_app_analytics)) as MaterialSwitch).isChecked ) Timber.d("Saving preferences") - // Set the repos in the ReposList realm db - val realmConfig = RealmConfiguration.Builder().name("ReposList.realm") - .encryptionKey(MainApplication.INSTANCE!!.key) - .directory(MainApplication.INSTANCE!!.getDataDirWithPath("realms")) - .schemaVersion(1).build() - val androidacyRepo = andRepoView.isChecked - val magiskAltRepo = magiskAltRepoView.isChecked - var realm = Realm.getInstance(realmConfig) - Timber.d("Realm instance: %s", realm) - if (realm.isInTransaction) { - realm.commitTransaction() - Timber.d("Committed last unfinished transaction") - } - // check if instance has been closed - if (realm.isClosed) { - Timber.d("Realm instance was closed, reopening") - realm = Realm.getInstance(realmConfig) - } - realm.executeTransactionAsync { r: Realm -> - Timber.d("Realm transaction started") - r.where(ReposList::class.java).equalTo("id", "androidacy_repo") - .findFirst()!!.isEnabled = androidacyRepo - r.where(ReposList::class.java).equalTo("id", "magisk_alt_repo") - .findFirst()!!.isEnabled = magiskAltRepo - Timber.d("Realm transaction committing") - // commit the changes - r.commitTransaction() - r.close() - Timber.d("Realm transaction committed") - } + // now basically do the same thing for room db + val db = Room.databaseBuilder( + applicationContext, + ReposListDatabase::class.java, "ReposList.db" + ).build() + val androidacyRepoRoom = andRepoView.isChecked + val magiskAltRepoRoom = magiskAltRepoView.isChecked + val reposListDao = db.reposListDao() + val androidacyRepoRoomObj = reposListDao.getById("androidacy_repo") + val magiskAltRepoRoomObj = reposListDao.getById("magisk_alt_repo") + reposListDao.setEnabled(androidacyRepoRoomObj.id, androidacyRepoRoom) + reposListDao.setEnabled(magiskAltRepoRoomObj.id, magiskAltRepoRoom) + db.close() editor.putString("last_shown_setup", "v3") // Commit the changes editor.commit() @@ -268,8 +247,8 @@ class SetupActivity : FoxActivity(), LanguageActivity { } // Log the changes Timber.d("Setup finished. Preferences: %s", prefs.all) - Timber.d("Androidacy repo: %s", androidacyRepo) - Timber.d("Magisk Alt repo: %s", magiskAltRepo) + Timber.d("Androidacy repo: %s", androidacyRepoRoom) + Timber.d("Magisk Alt repo: %s", magiskAltRepoRoom) // log last shown setup Timber.d("Last shown setup: %s", prefs.getString("last_shown_setup", "v0")) // Restart the activity @@ -384,7 +363,6 @@ class SetupActivity : FoxActivity(), LanguageActivity { FileUtils.forceMkdir(File(MainApplication.INSTANCE!!.dataDir.toString() + "/cache/cronet")) FileUtils.forceMkdir(File(MainApplication.INSTANCE!!.dataDir.toString() + "/cache/WebView/Default/HTTP Cache/Code Cache/wasm")) FileUtils.forceMkdir(File(MainApplication.INSTANCE!!.dataDir.toString() + "/cache/WebView/Default/HTTP Cache/Code Cache/js")) - FileUtils.forceMkdir(File(MainApplication.INSTANCE!!.dataDir.toString() + "/repos/magiskAltRepo")) } catch (e: IOException) { Timber.e(e) } @@ -393,7 +371,7 @@ class SetupActivity : FoxActivity(), LanguageActivity { @Suppress("KotlinConstantConditions") private fun disableUpdateActivityForFdroidFlavor() { - if (BuildConfig.FLAVOR == "fdroid") { + if (BuildConfig.FLAVOR == "fdroid" || BuildConfig.FLAVOR == "play") { // check if the update activity is enabled val pm = packageManager val componentName = ComponentName(this, UpdateActivity::class.java) diff --git a/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt b/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt index 5f3ab2f..41c0a38 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt @@ -26,6 +26,7 @@ import androidx.work.WorkManager import androidx.work.Worker import androidx.work.WorkerParameters import com.fox2code.mmm.AppUpdateManager +import com.fox2code.mmm.BuildConfig import com.fox2code.mmm.MainActivity import com.fox2code.mmm.MainApplication import com.fox2code.mmm.R @@ -53,7 +54,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters) private const val NOTFIICATION_GROUP = "updates" private const val NOTIFICATION_CHANNEL_ID_APP = "background_update_app" val lock = - Any() // Avoid concurrency issuespublic static final String NOTIFICATION_CHANNEL_ID = "background_update"; + Any() // Avoid concurrency issues private const val NOTIFICATION_ID_ONGOING = 2 private const val NOTIFICATION_CHANNEL_ID_ONGOING = "mmm_background_update" private const val NOTIFICATION_ID_APP = 3 @@ -111,7 +112,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters) } } - @Suppress("NAME_SHADOWING") + @Suppress("NAME_SHADOWING", "KotlinConstantConditions") fun doCheck(context: Context) { // first, check if the user has enabled background update checking if (!MainApplication.getSharedPreferences("mmm")!! @@ -280,14 +281,20 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters) if (MainApplication.getSharedPreferences("mmm")!! .getBoolean("pref_background_update_check_app", false) ) { - try { - val shouldUpdate = AppUpdateManager.appUpdateManager.checkUpdate(true) - if (shouldUpdate) { - Timber.d("Found app update") - postNotificationForAppUpdate(context) + + // don't check if app is from play store or fdroid + if (BuildConfig.FLAVOR != "play" || BuildConfig.FLAVOR != "fdroid") { + try { + val shouldUpdate = AppUpdateManager.appUpdateManager.checkUpdate(true) + if (shouldUpdate) { + Timber.d("Found app update") + postNotificationForAppUpdate(context) + } else { + Timber.d("No app update found") + } + } catch (e: Exception) { + Timber.e("Failed to check for app update") } - } catch (e: Exception) { - Timber.e("Failed to check for app update") } } // remove checking notification diff --git a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt index 8e89af0..ff63269 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt @@ -4,6 +4,7 @@ package com.fox2code.mmm.repo import android.net.Uri +import androidx.room.Room import com.fox2code.mmm.AppUpdateManager.Companion.shouldForceHide import com.fox2code.mmm.BuildConfig import com.fox2code.mmm.MainActivity @@ -13,16 +14,13 @@ import com.fox2code.mmm.XRepo import com.fox2code.mmm.manager.ModuleInfo import com.fox2code.mmm.utils.io.Files.Companion.write import com.fox2code.mmm.utils.io.PropUtils.Companion.readProperties -import com.fox2code.mmm.utils.realm.ModuleListCache -import com.fox2code.mmm.utils.realm.ReposList -import io.realm.Realm -import io.realm.RealmConfiguration +import com.fox2code.mmm.utils.room.ModuleListCacheDatabase +import com.fox2code.mmm.utils.room.ReposListDatabase import org.json.JSONException import org.json.JSONObject import timber.log.Timber import java.io.File import java.io.IOException -import java.util.concurrent.atomic.AtomicBoolean @Suppress("LeakingThis", "SENSELESS_COMPARISON", "RedundantSetter") open class RepoData(url: String, cacheRoot: File) : XRepo() { @@ -150,40 +148,20 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() { defaultName = url // Set url as default name val tempVarForPreferenceId = preferenceId!! isForceHide = shouldForceHide(tempVarForPreferenceId) - // this.enable is set from the database - 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) - val reposList = realm.where(ReposList::class.java).equalTo("id", preferenceId).findFirst() - if (reposList == null) { - Timber.d("RepoData for %s not found in database", preferenceId) - // log every repo in db - val fullList: Array = realm.where(ReposList::class.java).findAll().toTypedArray() - Timber.d("RepoData: " + preferenceId + ". repos in database: " + fullList.size) - for (repo in fullList) { - val r = repo as ReposList - Timber.d("RepoData: " + preferenceId + ". repo: " + r.id + " " + r.name + " " + r.website + " " + r.support + " " + r.donate + " " + r.submitModule + " " + r.isEnabled) - } - } else { - Timber.d("RepoData for %s found in database", preferenceId) - } - Timber.d( - "RepoData: $preferenceId. record in database: " + (reposList?.toString() - ?: "none") - ) - enabled = !isForceHide && reposList != null && reposList.isEnabled + // basically same as above but for room database + val db = Room.databaseBuilder( + INSTANCE!!.applicationContext, + ReposListDatabase::class.java, + "repo_database" + ).allowMainThreadQueries().build() + val reposListRoom = db.reposListDao() + val reposListRoomList = reposListRoom.getById(preferenceId!!) + enabled = !isForceHide && reposListRoomList != null && reposListRoomList.enabled defaultWebsite = "https://" + Uri.parse(url).host + "/" // open realm database // load metadata from realm database if (enabled) { try { - metaDataCache = ModuleListCache.getRepoModulesAsJson(preferenceId) - // log count of modules in the database - val tempMetaDataCacheVar = metaDataCache!! - Timber.d("RepoData: $preferenceId. modules in database: ${tempMetaDataCacheVar.length()}") // load repo metadata from ReposList unless it's a built-in repo if (RepoManager.isBuiltInRepo(preferenceId)) { name = defaultName @@ -192,28 +170,25 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() { donate = defaultDonate submitModule = defaultSubmitModule } else { - // get everything from ReposList realm database - name = realm.where( - ReposList::class.java - ).equalTo("id", preferenceId).findFirst()?.name - website = realm.where( - ReposList::class.java - ).equalTo("id", preferenceId).findFirst()?.website - support = realm.where( - ReposList::class.java - ).equalTo("id", preferenceId).findFirst()?.support - donate = realm.where( - ReposList::class.java - ).equalTo("id", preferenceId).findFirst()?.donate - submitModule = realm.where( - ReposList::class.java - ).equalTo("id", preferenceId).findFirst()?.submitModule + // get everything from the database + name = reposListRoomList.name + website = reposListRoomList.website + support = reposListRoomList.support + donate = reposListRoomList.donate + submitModule = reposListRoomList.submitModule + // if name is null return defaultName and if defaultName is null return url + if (name == null) { + name = if (defaultName == null) { + url + } else { + defaultName + } + } } } catch (e: Exception) { Timber.w("Failed to load repo metadata from database: " + e.message + ". If this is a first time run, this is normal.") } } - realm.close() } open fun prepare(): Boolean { @@ -330,27 +305,14 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() { get() = if (field) { field } else { - val realmConfiguration2 = - RealmConfiguration.Builder().name("ReposList.realm").encryptionKey( - INSTANCE!!.key - ).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory( - INSTANCE!!.getDataDirWithPath("realms") - ).schemaVersion(1).build() - val realm2 = Realm.getInstance(realmConfiguration2) - val dbEnabled = AtomicBoolean(false) - realm2.executeTransaction { realm: Realm -> - val reposList = - realm.where(ReposList::class.java).equalTo("id", preferenceId).findFirst() - if (reposList != null) { - dbEnabled.set(reposList.isEnabled) - } else { - // should never happen but for safety - dbEnabled.set(false) - } - } - realm2.close() + val db = Room.databaseBuilder( + INSTANCE!!.applicationContext, + ReposListDatabase::class.java, + "ReposList.db", + ).build() + val reposList = db.reposListDao().getById(preferenceId!!) // should never happen but for safety - if (dbEnabled.get()) { + if (reposList.enabled) { !isForceHide } else { false @@ -359,22 +321,13 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() { set(value) { field = value this.enabled = enabled && !isForceHide - // reposlist realm - val realmConfiguration2 = - RealmConfiguration.Builder().name("ReposList.realm").encryptionKey( - INSTANCE!!.key - ).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory( - INSTANCE!!.getDataDirWithPath("realms") - ).schemaVersion(1).build() - val realm2 = Realm.getInstance(realmConfiguration2) - realm2.executeTransaction { realm: Realm -> - val reposList = - realm.where(ReposList::class.java).equalTo("id", preferenceId).findFirst() - if (reposList != null) { - reposList.isEnabled = enabled - } - } - realm2.close() + val db = Room.databaseBuilder( + INSTANCE!!.applicationContext, + ReposListDatabase::class.java, + "ReposList.db", + ).build() + val reposList = db.reposListDao().getById(preferenceId!!) + db.reposListDao().update(name = reposList.name, enabled = value, id = reposList.id, donate = reposList.donate, support = reposList.support, website = reposList.website, submitModule = reposList.submitModule, lastUpdate = reposList.lastUpdate.toLong(), url = reposList.url) } @Throws(IOException::class) @@ -423,24 +376,17 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() { } // if repo starts with repo_, it's always enabled bc custom repos can't be disabled without being deleted. isForceHide = shouldForceHide(preferenceId!!) - // reposlist realm - val realmConfiguration2 = - RealmConfiguration.Builder().name("ReposList.realm").encryptionKey( - INSTANCE!!.key - ).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory( - INSTANCE!!.getDataDirWithPath("realms") - ).schemaVersion(1).build() - val realm2 = Realm.getInstance(realmConfiguration2) - var dbEnabled = false - try { - dbEnabled = realm2.where( - ReposList::class.java - ).equalTo("id", preferenceId).findFirst()?.isEnabled == true - } catch (e: Exception) { - Timber.e(e, "Error while updating enabled state for repo %s", preferenceId) + val db = Room.databaseBuilder( + INSTANCE!!.applicationContext, + ReposListDatabase::class.java, + "ReposList.db", + ).allowMainThreadQueries().build() + val reposList = db.reposListDao().getById(preferenceId!!) + enabled = if (reposList.enabled) { + !isForceHide + } else { + false } - realm2.close() - enabled = !isForceHide && dbEnabled } open fun getUrl(): String? { @@ -467,42 +413,35 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() { // should update (lastUpdate > 15 minutes) fun shouldUpdate(): Boolean { Timber.d("Repo $preferenceId should update check called") - val realmConfiguration2 = - RealmConfiguration.Builder().name("ReposList.realm").encryptionKey( - INSTANCE!!.key - ).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory( - INSTANCE!!.getDataDirWithPath("realms") - ).schemaVersion(1).build() - val realm2 = Realm.getInstance(realmConfiguration2) - val repo = realm2.where(ReposList::class.java).equalTo("id", preferenceId).findFirst() - // Make sure ModuleListCache for repoId is not null - val cacheRoot = INSTANCE!!.getDataDirWithPath("realms/repos/$preferenceId") - val realmConfiguration = - RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey( - INSTANCE!!.key - ).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true) - .allowQueriesOnUiThread(true).directory(cacheRoot).build() - val realm = Realm.getInstance(realmConfiguration) - val moduleListCache = realm.where( - ModuleListCache::class.java - ).equalTo("repoId", preferenceId).findAll() + val db = Room.databaseBuilder( + INSTANCE!!.applicationContext, + ReposListDatabase::class.java, + "ReposList.db", + ).allowMainThreadQueries().build() + val repo = db.reposListDao().getById(preferenceId!!) + // get modulelistcache + val db2 = Room.databaseBuilder( + INSTANCE!!.applicationContext, + ModuleListCacheDatabase::class.java, + "ModuleListCache.db", + ).allowMainThreadQueries().build() + val moduleListCache = db2.moduleListCacheDao().getByRepoId(preferenceId!!) if (repo != null) { - return if (repo.lastUpdate != 0 && moduleListCache.size != 0) { + return if (repo.lastUpdate != 0 && moduleListCache.isNotEmpty()) { val lastUpdate = repo.lastUpdate.toLong() val currentTime = System.currentTimeMillis() val diff = currentTime - lastUpdate val diffMinutes = diff / (60 * 1000) % 60 Timber.d("Repo $preferenceId updated: $diffMinutes minutes ago") - realm.close() diffMinutes > if (BuildConfig.DEBUG) 15 else 30 } else { Timber.d("Repo $preferenceId should update could not find repo in database") Timber.d("This is probably an error, please report this to the developer") - realm.close() true } } else { - realm.close() + db.close() + db2.close() } return true } diff --git a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt index cd33393..51ff77e 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt @@ -4,12 +4,11 @@ package com.fox2code.mmm.repo +import androidx.room.Room import com.fox2code.mmm.MainApplication import com.fox2code.mmm.utils.io.net.Http.Companion.doHttpGet -import com.fox2code.mmm.utils.realm.ModuleListCache -import com.fox2code.mmm.utils.realm.ReposList -import io.realm.Realm -import io.realm.RealmConfiguration +import com.fox2code.mmm.utils.room.ModuleListCacheDatabase +import com.fox2code.mmm.utils.room.ReposListDatabase import org.json.JSONArray import org.json.JSONObject import timber.log.Timber @@ -39,23 +38,15 @@ class RepoUpdater(repoData2: RepoData) { // if we shouldn't update, get the values from the ModuleListCache realm if (!repoData.shouldUpdate() && repoData.preferenceId == "androidacy_repo") { // for now, only enable cache reading for androidacy repo, until we handle storing module prop file values in cache Timber.d("Fetching index from cache for %s", repoData.preferenceId) - val cacheRoot = - MainApplication.INSTANCE!!.getDataDirWithPath("realms/repos/" + repoData.preferenceId) - val realmConfiguration = RealmConfiguration.Builder().name("ModuleListCache.realm") - .encryptionKey(MainApplication.INSTANCE!!.key).schemaVersion(1) - .deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true) - .allowQueriesOnUiThread(true).directory(cacheRoot).build() - val realm = Realm.getInstance(realmConfiguration) - val results = realm.where( - ModuleListCache::class.java - ).equalTo("repoId", repoData.preferenceId).findAll() - // repos-list realm - val realmConfiguration2 = RealmConfiguration.Builder().name("ReposList.realm") - .encryptionKey(MainApplication.INSTANCE!!.key).allowQueriesOnUiThread(true) - .allowWritesOnUiThread(true) - .directory(MainApplication.INSTANCE!!.getDataDirWithPath("realms")) - .schemaVersion(1).build() - val realm2 = Realm.getInstance(realmConfiguration2) + // now the above but for room + val db = Room.databaseBuilder( + MainApplication.INSTANCE!!, + ModuleListCacheDatabase::class.java, + "ModuleListCache.db" + ).allowMainThreadQueries().build() + val moduleListCacheDao = db.moduleListCacheDao() + // now we have the cache, we need to check if it's up to date + val results = moduleListCacheDao.getByRepoId(repoData.preferenceId!!) toUpdate = emptyList() toApply = HashSet() for (moduleListCache in results) { @@ -83,14 +74,11 @@ class RepoUpdater(repoData2: RepoData) { // apply the toApply list to the toUpdate list try { val jsonObject = JSONObject() - jsonObject.put("modules", JSONArray(results.asJSON())) + jsonObject.put("modules", JSONArray(results)) toUpdate = repoData.populate(jsonObject) } catch (e: Exception) { Timber.e(e) } - // close realm - realm.close() - realm2.close() // Since we reuse instances this should work toApply = HashSet(repoData.moduleHashMap.values) (toApply as HashSet).removeAll(toUpdate!!.toSet()) @@ -141,14 +129,13 @@ class RepoUpdater(repoData2: RepoData) { if (indexRaw != null) { try { // iterate over modules, using this.supportedProperties as a template to attempt to get each property from the module. everything that is not null is added to the module - // use realm to insert to + // use room to insert to // props avail: - val cacheRoot = - MainApplication.INSTANCE!!.getDataDirWithPath("realms/repos/" + repoData.preferenceId) - val realmConfiguration = RealmConfiguration.Builder().name("ModuleListCache.realm") - .encryptionKey(MainApplication.INSTANCE!!.key).schemaVersion(1) - .deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true) - .allowQueriesOnUiThread(true).directory(cacheRoot).build() + val db = Room.databaseBuilder( + MainApplication.INSTANCE!!, + ModuleListCacheDatabase::class.java, + "ModuleListCache.db" + ).allowMainThreadQueries().build() // array with module info default values // supported properties for a module //id= @@ -182,16 +169,8 @@ class RepoUpdater(repoData2: RepoData) { // get modules from "modules" key. This is a JSONArray so we need to convert it to a JSONObject modules.getJSONArray("modules") } - val realm = Realm.getInstance(realmConfiguration) - // drop old data - if (realm.isInTransaction) { - realm.commitTransaction() - } - realm.beginTransaction() - realm.where(ModuleListCache::class.java).equalTo("repoId", repoData.preferenceId) - .findAll() - .deleteAllFromRealm() - realm.commitTransaction() + val moduleListCacheDao = db.moduleListCacheDao() + moduleListCacheDao.deleteByRepoId(repoData.preferenceId!!) // iterate over modules. pls don't hate me for this, its ugly but it works for (n in 0 until modulesArray.length()) { // get module @@ -296,10 +275,6 @@ class RepoUpdater(repoData2: RepoData) { } // get module repo id val repoId = repoData.preferenceId - // get module installed - val installed = false - // get module installed version code - val installedVersionCode = 0 // get safe property. for now, only supported by androidacy repo and they use "vt_status" key var safe = false if (repoData.name == "Androidacy Modules Repo") { @@ -309,81 +284,22 @@ class RepoUpdater(repoData2: RepoData) { } } } - // insert module to realm - // first create a collection of all the properties - // then insert to realm - // then commit - // then close - if (realm.isInTransaction) { - realm.cancelTransaction() - } - // create a realm object and insert or update it - // add everything to the realm object - if (realm.isInTransaction) { - realm.commitTransaction() - } - realm.beginTransaction() - val moduleListCache = realm.createObject( - ModuleListCache::class.java, id - ) - moduleListCache.name = name - moduleListCache.version = version - moduleListCache.versionCode = versionCode - moduleListCache.author = author - moduleListCache.description = description - moduleListCache.minApi = minApiInt - moduleListCache.maxApi = maxApiInt - moduleListCache.minMagisk = minMagiskInt - moduleListCache.isNeedRamdisk = needRamdisk - moduleListCache.support = support - moduleListCache.donate = donate - moduleListCache.config = config - moduleListCache.isChangeBoot = changeBoot - moduleListCache.isMmtReborn = mmtReborn - moduleListCache.repoId = repoId - moduleListCache.isInstalled = installed - moduleListCache.installedVersionCode = installedVersionCode - moduleListCache.isSafe = safe - moduleListCache.lastUpdate = lastUpdate - moduleListCache.stats = downloads - realm.copyToRealmOrUpdate(moduleListCache) - realm.commitTransaction() + moduleListCacheDao.insert(name = name, version = version, versionCode = versionCode, author = author, description = description, minApi = minApiInt, maxApi = maxApiInt, minMagisk = minMagiskInt, needRamdisk = needRamdisk, support = support ?: "", donate = donate ?: "", config = config ?: "", changeBoot = changeBoot, mmtReborn = mmtReborn, repoId = repoId!!, safe = safe, lastUpdate = lastUpdate.toLong(), stats = downloads, codename = id ?: "") } catch (ignored: Exception) { } } - realm.close() } catch (ignored: Exception) { } indexRaw = null - val realmConfiguration2 = RealmConfiguration.Builder().name("ReposList.realm") - .encryptionKey(MainApplication.INSTANCE!!.key).allowQueriesOnUiThread(true) - .allowWritesOnUiThread(true) - .directory(MainApplication.INSTANCE!!.getDataDirWithPath("realms")) - .schemaVersion(1).build() - val realm2 = Realm.getInstance(realmConfiguration2) - if (realm2.isInTransaction) { - realm2.cancelTransaction() - } // set lastUpdate - realm2.executeTransaction { r: Realm -> - val repoListCache = - r.where(ReposList::class.java).equalTo("id", repoData.preferenceId).findFirst() - if (repoListCache != null) { - success.set(true) - // get unix timestamp of current time - val currentTime = (System.currentTimeMillis() / 1000).toInt() - Timber.d( - "Updating lastUpdate for repo %s to %s which is %s seconds ago", - repoData.preferenceId, - currentTime, - currentTime - repoListCache.lastUpdate - ) - repoListCache.lastUpdate = currentTime - } else { - Timber.w("Failed to update lastUpdate for repo %s", repoData.preferenceId) - } - } - realm2.close() + val db = Room.databaseBuilder( + MainApplication.INSTANCE!!.applicationContext, + ReposListDatabase::class.java, + "ReposList.db" + ).allowMainThreadQueries().build() + val repoListDao = db.reposListDao() + repoListDao.setLastUpdate(repoData.preferenceId!!, System.currentTimeMillis()) + db.close() } else { success.set(true) // assume we're reading from cache. this may be unsafe but it's better than nothing } diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.java index 74c6c07..81c162c 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.java @@ -48,6 +48,7 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceManager; import androidx.preference.SwitchPreferenceCompat; import androidx.preference.TwoStatePreference; +import androidx.room.Room; import androidx.security.crypto.EncryptedSharedPreferences; import androidx.security.crypto.MasterKey; @@ -75,7 +76,8 @@ import com.fox2code.mmm.utils.ExternalHelper; import com.fox2code.mmm.utils.IntentHelper; import com.fox2code.mmm.utils.ProcessHelper; import com.fox2code.mmm.utils.io.net.Http; -import com.fox2code.mmm.utils.realm.ReposList; +import com.fox2code.mmm.utils.room.ReposList; +import com.fox2code.mmm.utils.room.ReposListDatabase; import com.fox2code.mmm.utils.sentry.SentryMain; import com.fox2code.rosettax.LanguageActivity; import com.fox2code.rosettax.LanguageSwitcher; @@ -106,9 +108,6 @@ import java.util.Objects; import java.util.Random; import java.util.Set; -import io.realm.Realm; -import io.realm.RealmConfiguration; -import io.realm.RealmResults; import timber.log.Timber; public class SettingsActivity extends FoxActivity implements LanguageActivity { @@ -1071,28 +1070,13 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { return true; }); } - // Get magisk_alt_repo enabled state from realm db - RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); - Realm realm1 = Realm.getInstance(realmConfig); - ReposList reposList = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst(); - if (reposList != null) { - // Set the switch to the current state - SwitchPreferenceCompat magiskAltRepoEnabled = Objects.requireNonNull(findPreference("pref_magisk_alt_repo_enabled")); - magiskAltRepoEnabled.setChecked(reposList.isEnabled()); - } - // add listener to magisk_alt_repo_enabled switch to update realm db + // Get magisk_alt_repo enabled state from room reposlist db + ReposListDatabase db = Room.databaseBuilder(requireContext(), ReposListDatabase.class, "ReposList.db").allowMainThreadQueries().build(); + // add listener to magisk_alt_repo_enabled switch to update room db Preference magiskAltRepoEnabled = Objects.requireNonNull(findPreference("pref_magisk_alt_repo_enabled")); magiskAltRepoEnabled.setOnPreferenceChangeListener((preference, newValue) -> { - // Update realm db - Realm realm = Realm.getInstance(realmConfig); - realm.executeTransaction(realm2 -> { - ReposList reposList1 = realm2.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst(); - if (reposList1 != null) { - reposList1.setEnabled(Boolean.parseBoolean(String.valueOf(newValue))); - } else { - Timber.e("Alt Repo not found in realm db"); - } - }); + // Update room db + db.reposListDao().setEnabled("magisk_alt_repo", Boolean.parseBoolean(String.valueOf(newValue))); return true; }); // Disable toggling the pref_androidacy_repo_enabled on builds without an @@ -1107,37 +1091,21 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { }).show(); // Revert the switch to off androidacyRepoEnabled.setChecked(false); - // Disable in realm db - RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); - Realm realm = Realm.getInstance(realmConfiguration); - realm.executeTransaction(realm2 -> { - ReposList repoRealmResults = realm2.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst(); - assert repoRealmResults != null; - repoRealmResults.setEnabled(false); - realm2.insertOrUpdate(repoRealmResults); - realm2.close(); - }); + // Disable in room db + db.reposListDao().setEnabled("androidacy_repo", false); return false; }); } else { - // get if androidacy repo is enabled from realm db - RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); - Realm realm = Realm.getInstance(realmConfiguration); - ReposList repoRealmResults = realm.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst(); - if (repoRealmResults == null) { - throw new IllegalStateException("Androidacy repo not found in realm db"); - } - boolean androidacyRepoEnabledPref = repoRealmResults.isEnabled(); + // get if androidacy repo is enabled from room db + ReposList repoRealmResults = db.reposListDao().getById("androidacy_repo"); + boolean androidacyRepoEnabledPref = repoRealmResults.getEnabled(); // set the switch to the current state androidacyRepoEnabled.setChecked(androidacyRepoEnabledPref); // add a click listener to the switch androidacyRepoEnabled.setOnPreferenceClickListener(preference -> { boolean enabled = androidacyRepoEnabled.isChecked(); // save the new state - realm.executeTransaction(realm2 -> { - ReposList repoRealmResults1 = realm2.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst(); - repoRealmResults1.setEnabled(enabled); - }); + db.reposListDao().setEnabled("androidacy_repo", enabled); return true; }); if (androidacyRepoEnabledPref) { diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCache.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCache.kt index 1d485f9..bbd76de 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCache.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCache.kt @@ -25,8 +25,9 @@ class ModuleListCache ( var mmtReborn: Boolean, var repoId: String, var lastUpdate: Long, - val name: String, - var safe: Boolean + var name: String, + var safe: Boolean, + var stats: Int ) { // functions: // getAll(): List diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCacheDao.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCacheDao.kt index 354dd9e..7026aac 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCacheDao.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/room/ModuleListCacheDao.kt @@ -69,7 +69,7 @@ interface ModuleListCacheDao { fun getByCodename(codename: String): ModuleListCache @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, safe: Boolean, name: String) + 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, stats: Int) @Query("UPDATE modulelistcache SET version = :version WHERE codename = :codename") fun setVersion(codename: String, version: String) @@ -122,6 +122,9 @@ interface ModuleListCacheDao { @Query("UPDATE modulelistcache SET name = :name WHERE codename = :codename") fun setName(codename: String, name: String) + @Query("UPDATE modulelistcache SET stats = :stats WHERE codename = :codename") + fun setStats(codename: String, stats: Int) + @Query("DELETE FROM modulelistcache WHERE codename = :codename") fun delete(codename: String) @@ -182,10 +185,21 @@ interface ModuleListCacheDao { @Query("SELECT name FROM modulelistcache WHERE codename = :codename") fun getName(codename: String): String + @Query("SELECT stats FROM modulelistcache WHERE codename = :codename") + fun getStats(codename: String): Int + @Query("SELECT * FROM modulelistcache WHERE codename = :codename") fun get(codename: String): ModuleListCache // exists @Query("SELECT EXISTS(SELECT * FROM modulelistcache WHERE codename = :codename)") fun exists(codename: String): Boolean + + // asJson by repoId + @Query("SELECT * FROM modulelistcache WHERE repoId = :repoId") + fun asJson(repoId: String): List + + // delete by repoId + @Query("DELETE FROM modulelistcache WHERE repoId = :repoId") + fun deleteByRepoId(repoId: String) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/room/ReposListDao.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/room/ReposListDao.kt index 2076421..e12d59f 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/room/ReposListDao.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/room/ReposListDao.kt @@ -11,7 +11,7 @@ import androidx.room.Query @Dao interface ReposListDao { // contains - // id (string, primary), url (string), enabled (boolean), donate (string), support (string), submitMoulde (string), lastUpdate (bigint), name (string) and website (string) + // id (string, primary), url (string), enabled (boolean), donate (string), support (string), submitModule (string), lastUpdate (bigint), name (string) and website (string) // functions: // getAll(): List @@ -30,7 +30,7 @@ interface ReposListDao { 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") - 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?) @Query("DELETE FROM ReposList WHERE id = :id") fun delete(id: String)