diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ebbb7422..363154d3 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -158,6 +158,7 @@ dependencies {
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01")
implementation("androidx.viewpager2:viewpager2:1.1.0-beta02")
implementation("androidx.activity:activity-ktx:1.8.0-alpha06")
+ implementation("androidx.startup:startup-runtime:1.1.1")
val editorVersion = "0.22.0"
//noinspection GradleDependency
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index be0f5575..bbc9c081 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -53,6 +53,16 @@
android:resource="@xml/file_paths" />
+
+
+
+
diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/App.kt b/app/src/main/kotlin/org/cosmicide/rewrite/App.kt
index 3e66ad7f..fb55f13c 100644
--- a/app/src/main/kotlin/org/cosmicide/rewrite/App.kt
+++ b/app/src/main/kotlin/org/cosmicide/rewrite/App.kt
@@ -11,7 +11,6 @@ import android.app.Application
import android.app.UiModeManager
import android.content.res.Configuration
import android.os.Build
-import android.os.StrictMode
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
import androidx.recyclerview.widget.LinearLayoutManager
@@ -37,10 +36,13 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
import org.lsposed.hiddenapibypass.HiddenApiBypass
import rikka.sui.Sui
import java.io.File
+import java.io.FileInputStream
import java.io.FileNotFoundException
+import java.io.InputStream
import java.lang.ref.WeakReference
+import java.math.BigInteger
+import java.security.MessageDigest
import java.time.ZonedDateTime
-import java.util.concurrent.Executors
class App : Application() {
@@ -62,39 +64,9 @@ class App : Application() {
instance = WeakReference(this)
HookManager.context = WeakReference(this)
- val externalStorage = getExternalFilesDir(null)!!
-
- Prefs.init(applicationContext)
- FileUtil.init(externalStorage)
-
setupHooks()
loadPlugins()
- if (BuildConfig.DEBUG) {
- StrictMode.setVmPolicy(
- StrictMode.VmPolicy.Builder().apply {
- detectLeakedRegistrationObjects()
- detectActivityLeaks()
- detectContentUriWithoutPermission()
- detectFileUriExposure()
- detectCleartextNetwork()
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
- penaltyLog()
- return@apply
- }
- permitNonSdkApiUsage()
- penaltyListener(Executors.newSingleThreadExecutor()) { violation ->
- Log.e("StrictMode", "VM violation", violation)
- violation.printStackTrace()
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- detectIncorrectContextUse()
- detectUnsafeIntentLaunch()
- }
- }.build()
- )
- }
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
HiddenApiBypass.addHiddenApiExemptions("L")
}
@@ -142,9 +114,6 @@ class App : Application() {
* Extracts kotlin stdlib and stdlib-common from assets.
*/
fun extractFiles() {
- FileUtil.classpathDir.resolve("kotlin-stdlib-1.8.0.jar").apply {
- if (exists()) delete()
- }
extractAsset(
"kotlin-stdlib-1.9.0.jar",
FileUtil.classpathDir.resolve("kotlin-stdlib-1.9.0.jar")
@@ -156,7 +125,10 @@ class App : Application() {
}
fun extractAsset(assetName: String, targetFile: File) {
- targetFile.exists().ifTrue { return }
+ if (targetFile.exists() && assetNeedsUpdate(assetName, targetFile)) {
+ targetFile.delete()
+ }
+
try {
assets.open(assetName).use { inputStream ->
targetFile.outputStream().use { outputStream ->
@@ -168,6 +140,25 @@ class App : Application() {
}
}
+ fun assetNeedsUpdate(assetName: String, targetFile: File): Boolean {
+ val assetInputStream = assets.open(assetName)
+ val targetFileInputStream = FileInputStream(targetFile)
+ val assetChecksum = calculateChecksum(assetInputStream)
+ val targetFileChecksum = calculateChecksum(targetFileInputStream)
+ return assetChecksum != targetFileChecksum
+ }
+
+ fun calculateChecksum(inputStream: InputStream): String {
+ val md = MessageDigest.getInstance("SHA-256")
+ val buffer = ByteArray(8192)
+ var bytesRead: Int
+ while (inputStream.read(buffer).also { bytesRead = it } != -1) {
+ md.update(buffer, 0, bytesRead)
+ }
+ val digest = md.digest()
+ return BigInteger(1, digest).toString(16)
+ }
+
fun disableModules() {
JavacConfigProvider.disableModules()
}
@@ -186,7 +177,6 @@ class App : Application() {
}
private fun setupHooks() {
-
// Some libraries may call System.exit() to exit the app, which crashes the app.
// Currently, only JGit does this.
HookManager.registerHook(object : Hook(
@@ -223,8 +213,6 @@ class App : Application() {
param.result = null
}
})
-
-
}
override fun onConfigurationChanged(newConfig: Configuration) {
diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/startup/DebugInitializer.kt b/app/src/main/kotlin/org/cosmicide/rewrite/startup/DebugInitializer.kt
new file mode 100644
index 00000000..e30e83d5
--- /dev/null
+++ b/app/src/main/kotlin/org/cosmicide/rewrite/startup/DebugInitializer.kt
@@ -0,0 +1,45 @@
+package org.cosmicide.rewrite.startup
+
+import android.content.Context
+import android.os.Build
+import android.os.StrictMode
+import android.util.Log
+import androidx.startup.Initializer
+import org.cosmicide.rewrite.BuildConfig
+import java.util.concurrent.Executors
+
+class DebugInitializer : Initializer {
+
+ override fun create(context: Context) {
+ if (BuildConfig.DEBUG) {
+ enableStrictMode()
+ }
+ }
+
+ override fun dependencies(): List>> = emptyList()
+
+ private fun enableStrictMode() {
+ StrictMode.setVmPolicy(
+ StrictMode.VmPolicy.Builder().apply {
+ detectLeakedRegistrationObjects()
+ detectActivityLeaks()
+ detectContentUriWithoutPermission()
+ detectFileUriExposure()
+ detectCleartextNetwork()
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
+ penaltyLog()
+ return@apply
+ }
+ permitNonSdkApiUsage()
+ penaltyListener(Executors.newSingleThreadExecutor()) { violation ->
+ Log.e("StrictMode", "VM violation", violation)
+ violation.printStackTrace()
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ detectIncorrectContextUse()
+ detectUnsafeIntentLaunch()
+ }
+ }.build()
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/startup/MainInitializer.kt b/app/src/main/kotlin/org/cosmicide/rewrite/startup/MainInitializer.kt
new file mode 100644
index 00000000..d0b95ccc
--- /dev/null
+++ b/app/src/main/kotlin/org/cosmicide/rewrite/startup/MainInitializer.kt
@@ -0,0 +1,16 @@
+package org.cosmicide.rewrite.startup
+
+import android.content.Context
+import androidx.startup.Initializer
+
+class MainInitializer : Initializer {
+
+ override fun create(context: Context) {}
+
+ override fun dependencies(): List>> {
+ return listOf(
+ DebugInitializer::class.java,
+ PreferencesInitializer::class.java
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/startup/PreferencesInitializer.kt b/app/src/main/kotlin/org/cosmicide/rewrite/startup/PreferencesInitializer.kt
new file mode 100644
index 00000000..751f8e17
--- /dev/null
+++ b/app/src/main/kotlin/org/cosmicide/rewrite/startup/PreferencesInitializer.kt
@@ -0,0 +1,16 @@
+package org.cosmicide.rewrite.startup
+
+import android.content.Context
+import androidx.startup.Initializer
+import org.cosmicide.rewrite.common.Prefs
+import org.cosmicide.rewrite.util.FileUtil
+
+class PreferencesInitializer : Initializer {
+
+ override fun create(context: Context) {
+ FileUtil.init(context.getExternalFilesDir(null)!!)
+ Prefs.init(context.applicationContext)
+ }
+
+ override fun dependencies(): List>> = emptyList()
+}
\ No newline at end of file