diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 271e7f49c..4fc1aede8 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -234,6 +234,10 @@ dependencies {
// Debug utilities
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.10")
+ debugImplementation("com.plutolib:pluto:2.0.9")
+ releaseImplementation("com.plutolib:pluto-no-op:2.0.9")
+ debugImplementation("com.plutolib.plugins:bundle-core:2.0.9")
+ releaseImplementation("com.plutolib.plugins:bundle-core-no-op:2.0.9")
// Unit tests
testImplementation("junit:junit:4.13.2")
diff --git a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/MainApplication.kt b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/MainApplication.kt
index 7751c821a..bad42de86 100644
--- a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/MainApplication.kt
+++ b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/MainApplication.kt
@@ -7,8 +7,18 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.os.Build
+import android.os.StrictMode
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
+import com.pluto.Pluto
+import com.pluto.plugins.exceptions.PlutoExceptions
+import com.pluto.plugins.exceptions.PlutoExceptionsPlugin
+import com.pluto.plugins.logger.PlutoLoggerPlugin
+import com.pluto.plugins.logger.PlutoTimberTree
+import com.pluto.plugins.network.PlutoNetworkPlugin
+import com.pluto.plugins.preferences.PlutoSharePreferencesPlugin
+import com.pluto.plugins.rooms.db.PlutoRoomsDBWatcher
+import com.pluto.plugins.rooms.db.PlutoRoomsDatabasePlugin
import fr.bipi.tressence.file.FileLoggerTree
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
@@ -89,6 +99,7 @@ class MainApplication : Application(), SharedPreferences.OnSharedPreferenceChang
override fun onCreate() {
Timber.plant(DebugTree())
+ Timber.plant(PlutoTimberTree())
if(!BuildConfig.FOSS_ONLY)
Timber.plant(CrashReportingTree())
@@ -112,6 +123,49 @@ class MainApplication : Application(), SharedPreferences.OnSharedPreferenceChang
dumpFile.delete()
}
+ if(BuildConfig.DEBUG) {
+ // Setup strict mode with death penalty
+ StrictMode.setThreadPolicy(
+ StrictMode.ThreadPolicy.Builder()
+ .detectCustomSlowCalls()
+ .detectNetwork()
+ .detectResourceMismatches()
+ .penaltyLog()
+ .penaltyDeath()
+ .build()
+ )
+
+ StrictMode.setVmPolicy(
+ StrictMode.VmPolicy.Builder()
+ .apply {
+ detectLeakedRegistrationObjects()
+ detectCleartextNetwork()
+ detectActivityLeaks()
+ detectLeakedClosableObjects()
+ detectLeakedSqlLiteObjects()
+ detectContentUriWithoutPermission()
+ penaltyLog()
+ penaltyDeath()
+ }
+ .build()
+ )
+
+ Pluto.Installer(this)
+ .addPlugin(PlutoNetworkPlugin("network"))
+ .addPlugin(PlutoExceptionsPlugin("exceptions"))
+ .addPlugin(PlutoLoggerPlugin("logger"))
+ .addPlugin(PlutoSharePreferencesPlugin("sharedPref"))
+ .addPlugin(PlutoRoomsDatabasePlugin("rooms-db"))
+ .install()
+ Pluto.showNotch(true)
+
+ PlutoExceptions.setANRHandler { thread, exception ->
+ Timber.e("unhandled ANR handled on thread: " + thread.name, exception)
+ }
+
+ PlutoRoomsDBWatcher.watch("blocked_apps.db", AppBlocklistDatabase::class.java)
+ }
+
Notifications.createChannels(this)
val appModule = module {
diff --git a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/api/AutoEqClient.kt b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/api/AutoEqClient.kt
index fab8a2b83..af3e736b8 100644
--- a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/api/AutoEqClient.kt
+++ b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/api/AutoEqClient.kt
@@ -1,6 +1,7 @@
package me.timschneeberger.rootlessjamesdsp.api
import android.content.Context
+import com.pluto.plugins.network.PlutoInterceptor
import me.timschneeberger.rootlessjamesdsp.BuildConfig
import me.timschneeberger.rootlessjamesdsp.R
import me.timschneeberger.rootlessjamesdsp.flavor.CrashlyticsImpl
@@ -25,6 +26,7 @@ class AutoEqClient(val context: Context, callTimeout: Long = 10, customBaseUrl:
private val http = OkHttpClient
.Builder()
.callTimeout(callTimeout, TimeUnit.SECONDS)
+ .addInterceptor(PlutoInterceptor())
.addInterceptor(UserAgentInterceptor("RootlessJamesDSP v${BuildConfig.VERSION_NAME}"))
.build()
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 86210c9a5..33d58f3e6 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -22,7 +22,7 @@
-
+
diff --git a/app/src/root/java/me/timschneeberger/rootlessjamesdsp/flavor/updates/api/UpdateCheckClient.kt b/app/src/root/java/me/timschneeberger/rootlessjamesdsp/flavor/updates/api/UpdateCheckClient.kt
index aa8bbfb83..2016a1e63 100644
--- a/app/src/root/java/me/timschneeberger/rootlessjamesdsp/flavor/updates/api/UpdateCheckClient.kt
+++ b/app/src/root/java/me/timschneeberger/rootlessjamesdsp/flavor/updates/api/UpdateCheckClient.kt
@@ -1,6 +1,7 @@
package me.timschneeberger.rootlessjamesdsp.flavor.updates.api
import android.content.Context
+import com.pluto.plugins.network.PlutoInterceptor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -27,6 +28,7 @@ class UpdateCheckClient(val context: Context, callTimeout: Long = 10): KoinCompo
private val http = OkHttpClient
.Builder()
.callTimeout(callTimeout, TimeUnit.SECONDS)
+ .addInterceptor(PlutoInterceptor())
.addInterceptor(UserAgentInterceptor("RootlessJamesDSP v${BuildConfig.VERSION_NAME}"))
.build()