@@ -103,87 +103,11 @@ class GramophoneApplication : Application(), SingletonImageLoader.Factory,
103103 // disk read and write on first launch, but unavoidable as threads would race setDefaultNightMode
104104 val prefs = PreferenceManager .getDefaultSharedPreferences(this )
105105 if (BuildConfig .DEBUG ) {
106- // Use StrictMode to find anti-pattern issues
107- StrictMode .setThreadPolicy(
108- ThreadPolicy .Builder ()
109- .detectAll()
110- .let {
111- if (Build .VERSION .SDK_INT == Build .VERSION_CODES .UPSIDE_DOWN_CAKE ||
112- Build .VERSION .SDK_INT == Build .VERSION_CODES .VANILLA_ICE_CREAM
113- ) {
114- it.permitExplicitGc() // platform bug, now fixed
115- } else it
116- }
117- .let {
118- if (Debug .isDebuggerConnected() || isAlpsBoostFwkPresent())
119- it.permitDiskReads()
120- else it
121- }
122- .penaltyLog()
123- .penaltyDialog()
124- .build()
125- )
126- StrictMode .setVmPolicy(
127- VmPolicy .Builder ()
128- .detectAll()
129- // detectAll does in fact not detect everything :)
130- .let {
131- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
132- it.detectImplicitDirectBoot()
133- } else it
134- }
135- .penaltyLog()
136- .penaltyDeath()
137- .build()
138- )
139- FragmentStrictMode .defaultPolicy = FragmentStrictMode .Policy .Builder ()
140- .detectFragmentReuse()
141- .detectFragmentTagUsage()
142- .detectRetainInstanceUsage()
143- .detectSetUserVisibleHint()
144- // .detectTargetFragmentUsage() TODO onDisplayPreferenceDialog()
145- .detectWrongFragmentContainer()
146- .detectWrongNestedHierarchy()
147- .penaltyDeath()
148- .build()
106+ setupStrictMode()
107+ setupFragmentStrictMode()
149108 }
150109 android.util.Log .d(TAG , " GramophoneApplication.onCreate()" )
151- if (! android.util.Log .isLoggable(TAG , android.util.Log .INFO )) {
152- Log .setLogger(object : Log .Logger {
153- override fun d (
154- tag : String ,
155- message : String ,
156- throwable : Throwable ?
157- ) {
158- android.util.Log .e(tag, " [DEBUG] $message " , throwable)
159- }
160-
161- override fun i (
162- tag : String ,
163- message : String ,
164- throwable : Throwable ?
165- ) {
166- android.util.Log .e(tag, " [INFO] $message " , throwable)
167- }
168-
169- override fun w (
170- tag : String ,
171- message : String ,
172- throwable : Throwable ?
173- ) {
174- android.util.Log .e(tag, " [WARN] $message " , throwable)
175- }
176-
177- override fun e (
178- tag : String ,
179- message : String ,
180- throwable : Throwable ?
181- ) {
182- android.util.Log .e(tag, " [ERROR] $message " , throwable)
183- }
184-
185- })
186- }
110+ setupMedia3Logger()
187111 uacManager = UacManager (this )
188112 Flags .PLAYLIST_EDITING = prefs.getBooleanStrict(" playlist_editing" , false )
189113 reader = FlowReader (
@@ -196,20 +120,8 @@ class GramophoneApplication : Application(), SingletonImageLoader.Factory,
196120 recentlyAddedFilterSecondFlow,
197121 MutableStateFlow (true ), " gramophoneAlbumCover"
198122 )
199- // Set application theme when launching.
200- when (prefs.getString(" theme_mode" , " 0" )) {
201- " 0" -> {
202- AppCompatDelegate .setDefaultNightMode(AppCompatDelegate .MODE_NIGHT_FOLLOW_SYSTEM )
203- }
204-
205- " 1" -> {
206- AppCompatDelegate .setDefaultNightMode(AppCompatDelegate .MODE_NIGHT_YES )
207- }
208-
209- " 2" -> {
210- AppCompatDelegate .setDefaultNightMode(AppCompatDelegate .MODE_NIGHT_NO )
211- }
212- }
123+ setupTheme(prefs)
124+
213125 // This is a separate thread to avoid disk read on main thread and improve startup time
214126 CoroutineScope (Dispatchers .Default ).launch {
215127 onSharedPreferenceChanged(prefs, null ) // reload all values
@@ -225,14 +137,84 @@ class GramophoneApplication : Application(), SingletonImageLoader.Factory,
225137 }
226138 }
227139
140+ private fun setupStrictMode () {
141+ StrictMode .setThreadPolicy(
142+ ThreadPolicy .Builder ()
143+ .detectAll()
144+ .let {
145+ if (Build .VERSION .SDK_INT == Build .VERSION_CODES .UPSIDE_DOWN_CAKE ||
146+ Build .VERSION .SDK_INT == Build .VERSION_CODES .VANILLA_ICE_CREAM
147+ ) {
148+ it.permitExplicitGc() // platform bug, now fixed
149+ } else it
150+ }
151+ .let {
152+ if (Debug .isDebuggerConnected() || isAlpsBoostFwkPresent())
153+ it.permitDiskReads()
154+ else it
155+ }
156+ .penaltyLog()
157+ .penaltyDialog()
158+ .build()
159+ )
160+ StrictMode .setVmPolicy(
161+ VmPolicy .Builder ()
162+ .detectAll()
163+ .let {
164+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
165+ it.detectImplicitDirectBoot()
166+ } else it
167+ }
168+ .penaltyLog()
169+ .penaltyDeath()
170+ .build()
171+ )
172+ }
173+
174+ private fun setupFragmentStrictMode () {
175+ FragmentStrictMode .defaultPolicy = FragmentStrictMode .Policy .Builder ()
176+ .detectFragmentReuse()
177+ .detectFragmentTagUsage()
178+ .detectRetainInstanceUsage()
179+ .detectSetUserVisibleHint()
180+ .detectWrongFragmentContainer()
181+ .detectWrongNestedHierarchy()
182+ .penaltyDeath()
183+ .build()
184+ }
185+
186+ private fun setupMedia3Logger () {
187+ if (! android.util.Log .isLoggable(TAG , android.util.Log .INFO )) {
188+ Log .setLogger(object : Log .Logger {
189+ override fun d (tag : String , message : String , throwable : Throwable ? ) {
190+ android.util.Log .e(tag, " [DEBUG] $message " , throwable)
191+ }
192+ override fun i (tag : String , message : String , throwable : Throwable ? ) {
193+ android.util.Log .e(tag, " [INFO] $message " , throwable)
194+ }
195+ override fun w (tag : String , message : String , throwable : Throwable ? ) {
196+ android.util.Log .e(tag, " [WARN] $message " , throwable)
197+ }
198+ override fun e (tag : String , message : String , throwable : Throwable ? ) {
199+ android.util.Log .e(tag, " [ERROR] $message " , throwable)
200+ }
201+ })
202+ }
203+ }
204+
205+ private fun setupTheme (prefs : SharedPreferences ) {
206+ when (prefs.getString(" theme_mode" , " 0" )) {
207+ " 0" -> AppCompatDelegate .setDefaultNightMode(AppCompatDelegate .MODE_NIGHT_FOLLOW_SYSTEM )
208+ " 1" -> AppCompatDelegate .setDefaultNightMode(AppCompatDelegate .MODE_NIGHT_YES )
209+ " 2" -> AppCompatDelegate .setDefaultNightMode(AppCompatDelegate .MODE_NIGHT_NO )
210+ }
211+ }
212+
228213 override fun onSharedPreferenceChanged (prefs : SharedPreferences , key : String? ) {
229214 runBlocking {
230215 if (key == null || key == " mediastore_filter" ) {
231216 minSongLengthSecondsFlow.emit(
232- prefs.getInt(
233- " mediastore_filter" ,
234- resources.getInteger(R .integer.filter_default_sec)
235- ).toLong()
217+ prefs.getInt(" mediastore_filter" , resources.getInteger(R .integer.filter_default_sec)).toLong()
236218 )
237219 }
238220 if (key == null || key == " folderFilter" ) {
@@ -257,46 +239,38 @@ class GramophoneApplication : Application(), SingletonImageLoader.Factory,
257239 add(CoilArtPipeline .ArtResourceKeyer ())
258240 add(CoilArtPipeline .ArtResourceFetcher .Factory ())
259241 }
260- .run {
261- if (! BuildConfig .DEBUG ) this else
262- logger(object : Logger {
263- override var minLevel = Logger .Level .Verbose
264- override fun log (
265- tag : String ,
266- level : Logger .Level ,
267- message : String? ,
268- throwable : Throwable ?
269- ) {
270- if (level < minLevel) return
271- val println = { it: String ->
272- when (level) {
273- Logger .Level .Verbose -> Log .d(tag, it)
274- Logger .Level .Debug -> Log .d(tag, it)
275- Logger .Level .Info -> Log .i(tag, it)
276- Logger .Level .Warn -> Log .w(tag, it)
277- Logger .Level .Error -> Log .e(tag, it)
278- }
279- }
280- if (message != null ) {
281- println (message)
282- }
283- // Let's keep the log readable and ignore normal events' stack traces.
284- if (throwable != null && throwable !is NullRequestDataException
285- && (throwable !is IOException
286- || throwable.message != " No album art found" )
287- ) {
288- println (Log .getThrowableString(throwable)!! )
289- }
290- }
291- })
242+ .apply {
243+ if (BuildConfig .DEBUG ) {
244+ logger(createDebugLogger())
245+ }
292246 }
293247 .build()
294248 }
295249
250+ private fun createDebugLogger () = object : Logger {
251+ override var minLevel = Logger .Level .Verbose
252+ override fun log (tag : String , level : Logger .Level , message : String? , throwable : Throwable ? ) {
253+ if (level < minLevel) return
254+ message?.let { printLog(tag, level, it) }
255+ if (throwable != null && throwable !is NullRequestDataException &&
256+ (throwable !is IOException || throwable.message != " No album art found" )
257+ ) {
258+ printLog(tag, level, Log .getThrowableString(throwable)!! )
259+ }
260+ }
261+
262+ private fun printLog (tag : String , level : Logger .Level , msg : String ) {
263+ when (level) {
264+ Logger .Level .Verbose -> Log .d(tag, msg)
265+ Logger .Level .Debug -> Log .d(tag, msg)
266+ Logger .Level .Info -> Log .i(tag, msg)
267+ Logger .Level .Warn -> Log .w(tag, msg)
268+ Logger .Level .Error -> Log .e(tag, msg)
269+ }
270+ }
271+ }
272+
296273 override fun uncaughtException (t : Thread , e : Throwable ) {
297- // TODO convert to notification that opens BugHandlerActivity on click, and let JVM
298- // go through the normal exception process (to get stats from play). disadvantage: we can't
299- // cheat the statistic that way
300274 val exceptionMessage = Log .getThrowableString(e)
301275 val threadName = Thread .currentThread().name
302276 Log .e(TAG , " Error on thread $threadName :\n $exceptionMessage " )
0 commit comments