Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logger and refactor code #280

Merged
merged 5 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2'
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.7.0-alpha02'
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.7.0-beta01'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.browser:browser:1.6.0'
Expand All @@ -145,32 +145,32 @@ dependencies {
//Image downloading and Caching library
implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation "com.github.bumptech.glide:compose:1.0.0-alpha.3"
implementation 'io.coil-kt:coil-compose:2.4.0'
implementation 'io.coil-kt:coil-compose:2.5.0'
implementation 'com.caverock:androidsvg-aar:1.4'
ksp 'com.github.bumptech.glide:compiler:4.16.0'

//Permissions
implementation "com.google.accompanist:accompanist-permissions:$accompanist_version"

//Design Setup
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.google.android.material:material:1.10.0'
implementation 'com.airbnb.android:lottie:6.1.0'
implementation 'com.github.akshaaatt:Onboarding:1.1.2'
implementation 'com.github.akshaaatt:Share-Android:1.0.0'
implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'
implementation 'androidx.hilt:hilt-navigation-compose:1.1.0'
implementation 'com.airbnb.android:lottie-compose:6.1.0'

//Dagger-Hilt
implementation("com.google.dagger:hilt-android:$hilt_version")
kapt("com.google.dagger:hilt-android-compiler:$hilt_version")
kapt("androidx.hilt:hilt-compiler:1.0.0")
implementation 'androidx.hilt:hilt-work:1.0.0'
kapt('androidx.hilt:hilt-compiler:1.1.0')
implementation 'androidx.hilt:hilt-work:1.1.0'
implementation "androidx.startup:startup-runtime:1.1.1"
androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
kaptAndroidTest "com.google.dagger:hilt-android-compiler:$hilt_version"

//Jetpack Compose
implementation platform('androidx.compose:compose-bom:2023.09.02')
implementation platform('androidx.compose:compose-bom:2023.10.01')
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-tooling'
Expand All @@ -191,7 +191,7 @@ dependencies {
implementation files('./lib/spotify-app-remote-release-0.7.2.aar')

// HTML Parser for retrieving token
implementation "org.jsoup:jsoup:1.16.1"
implementation 'org.jsoup:jsoup:1.16.2'

//Socket IO
implementation ('io.socket:socket.io-client:2.1.0') {
Expand All @@ -207,11 +207,11 @@ dependencies {
testImplementation 'androidx.arch.core:core-testing:2.2.0'

// Mockito framework
testImplementation 'org.mockito:mockito-core:5.5.0'
testImplementation 'org.mockito:mockito-core:5.7.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.1.0'

debugImplementation "androidx.test:monitor:1.6.1" // Solves "class PlatformTestStorageRegistery not found" error for ui tests.
debugImplementation "androidx.compose.ui:ui-test-manifest:1.5.3"
debugImplementation 'androidx.compose.ui:ui-test-manifest:1.5.4'

androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
androidTestImplementation "androidx.work:work-testing:$work_version"
Expand Down Expand Up @@ -250,4 +250,5 @@ dependencies {
// Third party libraries
implementation 'com.github.dariobrux:Timer:1.1.0'
implementation 'com.github.a914-gowtham:compose-ratingbar:1.3.4'
implementation 'com.github.akshaaatt:Logger-Android:1.0.0'
}
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@
<meta-data
android:name="io.sentry.traces.user-interaction.enable"
android:value="true" />

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>

</application>

</manifest>
99 changes: 98 additions & 1 deletion app/src/main/java/org/listenbrainz/android/application/App.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
package org.listenbrainz.android.application

import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Intent
import android.os.Build
import android.os.StrictMode
import androidx.core.content.ContextCompat
import androidx.hilt.work.HiltWorkerFactory
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Configuration
import com.limurse.logger.Logger
import com.limurse.logger.config.Config
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.listenbrainz.android.BuildConfig
import org.listenbrainz.android.R
import org.listenbrainz.android.repository.preferences.AppPreferences
import org.listenbrainz.android.service.ListenScrobbleService
import org.listenbrainz.android.util.Constants
import javax.inject.Inject

@HiltAndroidApp
Expand All @@ -24,6 +34,20 @@ class App : Application(), Configuration.Provider {

override fun onCreate() {
super.onCreate()
val logDirectory = applicationContext.getExternalFilesDir(null)?.path.orEmpty()
val config = Config.Builder(logDirectory)
.setDefaultTag(Constants.TAG)
.setLogcatEnable(true)
.setDataFormatterPattern("dd-MM-yyyy-HH:mm:ss")
.setStartupData(collectStartupData())
.build()

Logger.init(config)

if (BuildConfig.DEBUG) {
enableStrictMode()
}

context = this

MainScope().launch {
Expand All @@ -35,8 +59,81 @@ class App : Application(), Configuration.Provider {
startListenService()
}
}

createChannels()
}


private fun collectStartupData(): Map<String, String> = mapOf(
"App Version" to System.currentTimeMillis().toString(),
"Device Application Id" to BuildConfig.APPLICATION_ID,
"Device Version Code" to BuildConfig.VERSION_CODE.toString(),
"Device Version Name" to BuildConfig.VERSION_NAME,
"Device Build Type" to BuildConfig.BUILD_TYPE,
"Device" to Build.DEVICE,
"Device SDK" to Build.VERSION.SDK_INT.toString(),
"Device Manufacturer" to Build.MANUFACTURER
)

private fun createChannels() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
return

val nm = ContextCompat.getSystemService(this, NotificationManager::class.java)!!

val channels = nm.notificationChannels

// delete old channels, if they exist
if (channels?.any { it.id == "foreground" } == true) {
channels.forEach { nm.deleteNotificationChannel(it.id) }
}

nm.createNotificationChannel(
NotificationChannel(
Constants.Strings.CHANNEL_NOTI_SCROBBLING,
getString(R.string.state_scrobbling), NotificationManager.IMPORTANCE_LOW
)
)
nm.createNotificationChannel(
NotificationChannel(
Constants.Strings.CHANNEL_NOTI_SCR_ERR,
getString(R.string.channel_err), NotificationManager.IMPORTANCE_MIN
)
)
nm.createNotificationChannel(
NotificationChannel(
Constants.Strings.CHANNEL_NOTI_NEW_APP,
getString(R.string.new_player, getString(R.string.new_app)),
NotificationManager.IMPORTANCE_LOW
)
)
nm.createNotificationChannel(
NotificationChannel(
Constants.Strings.CHANNEL_NOTI_PENDING,
getString(R.string.pending_scrobbles), NotificationManager.IMPORTANCE_MIN
)
)
}

private fun enableStrictMode() {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyFlashScreen()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectFileUriExposure()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.build()
)
}

override fun getWorkManagerConfiguration(): Configuration =
Configuration.Builder()
.setWorkerFactory(workerFactory)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
package org.listenbrainz.android.service

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.ComponentName
import android.content.Intent
import android.media.session.MediaSessionManager
import android.os.Build
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import androidx.core.content.ContextCompat
import androidx.work.WorkManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import org.listenbrainz.android.repository.listens.ListensRepository
import org.listenbrainz.android.repository.preferences.AppPreferences
import org.listenbrainz.android.util.Constants.Strings.CHANNEL_ID
import org.listenbrainz.android.util.ListenSessionListener
import org.listenbrainz.android.util.Log.d
import org.listenbrainz.android.util.Log.e
import javax.inject.Inject

@AndroidEntryPoint
Expand All @@ -33,6 +39,12 @@ class ListenScrobbleService : NotificationListenerService() {
private var sessionListener: ListenSessionListener? = null
private var listenServiceComponent: ComponentName? = null
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private val nm by lazy {
ContextCompat.getSystemService(
this,
NotificationManager::class.java
)!!
}

override fun onCreate() {
super.onCreate()
Expand All @@ -46,22 +58,15 @@ class ListenScrobbleService : NotificationListenerService() {
sessionManager = applicationContext.getSystemService(MEDIA_SESSION_SERVICE) as MediaSessionManager
sessionListener = ListenSessionListener(appPreferences, workManager, scope)
listenServiceComponent = ComponentName(this, this.javaClass)

createNotificationChannel()

try {
sessionManager?.addOnActiveSessionsChangedListener(
sessionListener!!,
listenServiceComponent
)
sessionManager?.addOnActiveSessionsChangedListener(sessionListener!!, listenServiceComponent)
} catch (e: SecurityException) {
e("Could not add session listener due to security exception: ${e.message}")
} catch (e: Exception) {
e.printStackTrace()
// Remove orphan entries.
try {
sessionManager?.removeOnActiveSessionsChangedListener(sessionListener!!)
} catch (e: Exception) {
e.printStackTrace()
}
e("Could not add session listener: ${e.message}")
}

}

override fun onDestroy() {
Expand All @@ -78,4 +83,19 @@ class ListenScrobbleService : NotificationListenerService() {
override fun onNotificationRemoved(sbn: StatusBarNotification) {
super.onNotificationRemoved(sbn)
}

companion object {
private const val CHANNEL_NAME = "Scrobbling"
private const val CHANNEL_DESCRIPTION = "Shows notifications when a song is played"
}

private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_LOW
val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance).apply {
description = CHANNEL_DESCRIPTION
}
nm.createNotificationChannel(channel)
}
}
}
Loading