From 60949838c5284206c90a3f784251de00ff3637ce Mon Sep 17 00:00:00 2001 From: kshivang Date: Mon, 30 Sep 2019 17:56:46 +0530 Subject: [PATCH] local playback done --- app/build.gradle | 4 +- .../rever/goonjexample/AudioPlayerActivity.kt | 4 +- .../ai/rever/goonjexample/GoonjExampleApp.kt | 34 ++++++++++++--- goonj/build.gradle | 2 - goonj/src/main/java/ai/rever/goonj/Goonj.kt | 8 +++- .../goonj/manager/GoonjNotificationManager.kt | 10 +++-- .../rever/goonj/manager/GoonjPlayerManager.kt | 1 - .../main/java/ai/rever/goonj/models/Track.kt | 42 ++++++++++++++++--- .../ai/rever/goonj/player/LocalAudioPlayer.kt | 28 ++++++++----- 9 files changed, 100 insertions(+), 33 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d561947..9b49e10 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,9 +51,7 @@ dependencies { implementation 'com.google.android.material:material:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' - // Picasso - implementation 'com.squareup.picasso:picasso:2.71828' - + // Glide implementation 'com.github.bumptech.glide:glide:4.9.0' } diff --git a/app/src/main/java/ai/rever/goonjexample/AudioPlayerActivity.kt b/app/src/main/java/ai/rever/goonjexample/AudioPlayerActivity.kt index 12c7dfb..979cdad 100644 --- a/app/src/main/java/ai/rever/goonjexample/AudioPlayerActivity.kt +++ b/app/src/main/java/ai/rever/goonjexample/AudioPlayerActivity.kt @@ -15,7 +15,6 @@ import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.cast.framework.CastButtonFactory import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability -import com.squareup.picasso.Picasso import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo import java.lang.Exception @@ -66,7 +65,8 @@ class AudioPlayerActivity : AppCompatActivity(), GoonjPlayer { private fun onPlayingTrackChange(currentItem: Track) { if (knownTrack.id != currentItem.id) { - Picasso.get().load(currentItem.imageUrl).into(audioPlayerAlbumArtIV) +// Picasso.get().load(currentItem.imageUrl).into(audioPlayerAlbumArtIV) + currentItem.load { audioPlayerAlbumArtIV.setImageBitmap(it) } audioPlayerAlbumTitleTv.text = currentItem.title audioPlayerAlbumArtistTv.text = currentItem.artistName } diff --git a/app/src/main/java/ai/rever/goonjexample/GoonjExampleApp.kt b/app/src/main/java/ai/rever/goonjexample/GoonjExampleApp.kt index 2710e10..fcbd817 100644 --- a/app/src/main/java/ai/rever/goonjexample/GoonjExampleApp.kt +++ b/app/src/main/java/ai/rever/goonjexample/GoonjExampleApp.kt @@ -1,13 +1,17 @@ package ai.rever.goonjexample import ai.rever.goonj.Goonj +import ai.rever.goonj.models.Track import android.app.Application import android.content.Intent +import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.OnLifecycleEvent -import androidx.lifecycle.ProcessLifecycleOwner +import androidx.core.graphics.drawable.toBitmap +import androidx.lifecycle.* +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition class GoonjExampleApp: Application(), LifecycleObserver { @@ -22,7 +26,8 @@ class GoonjExampleApp: Application(), LifecycleObserver { Goonj.initialize(this) .setPendingIntentForNotification(pendingIntent) - .addOnTrackComplete { } + .addOnTrackComplete(::onTrackComplete) + .setImageLoader(::imageLoader) } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) @@ -31,5 +36,24 @@ class GoonjExampleApp: Application(), LifecycleObserver { Goonj.unregister() } + + private fun imageLoader(track: Track, callback: (Bitmap?) -> Unit) { + Glide.with(this).asBitmap().load(track.imageUrl) + .into(object : CustomTarget(){ + override fun onResourceReady(resource: Bitmap, + transition: Transition?) { + callback(resource) + } + + override fun onLoadCleared(placeholder: Drawable?) { + callback(placeholder?.toBitmap()) + } + }) + + } + + private fun onTrackComplete(track: Track) { + + } } diff --git a/goonj/build.gradle b/goonj/build.gradle index 1240d37..828ef46 100644 --- a/goonj/build.gradle +++ b/goonj/build.gradle @@ -56,7 +56,6 @@ dependencies { implementation 'com.google.android.gms:play-services-cast-framework:17.1.0' - // Architecture components implementation 'android.arch.work:work-runtime-ktx:1.0.1' implementation "android.arch.persistence.room:runtime:1.1.1" @@ -66,7 +65,6 @@ dependencies { api "io.reactivex.rxjava2:rxkotlin:2.4.0" api 'io.reactivex.rxjava2:rxandroid:2.1.1' - // Exo LocalAudioPlayer implementation 'com.google.android.exoplayer:exoplayer-core:2.10.3' implementation 'com.google.android.exoplayer:exoplayer-ui:2.10.3' diff --git a/goonj/src/main/java/ai/rever/goonj/Goonj.kt b/goonj/src/main/java/ai/rever/goonj/Goonj.kt index 558bb22..d7cec42 100644 --- a/goonj/src/main/java/ai/rever/goonj/Goonj.kt +++ b/goonj/src/main/java/ai/rever/goonj/Goonj.kt @@ -9,6 +9,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection +import android.graphics.Bitmap import android.os.IBinder import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers @@ -27,7 +28,7 @@ object Goonj { internal val appContext get() = weakContext?.get() private var weakContext: WeakReference? = null - + internal var imageLoader: ((Track, (Bitmap?) -> Unit) -> Unit)? = null private var holderGoonjPlayerServiceInterface: WeakReference? = null @@ -64,6 +65,11 @@ object Goonj { return this } + fun setImageLoader(imageLoader: (Track, (Bitmap?) -> Unit) -> Unit): Goonj { + this.imageLoader = imageLoader + return this + } + fun setPendingIntentForNotification(intent: Intent): Goonj { run { GoonjNotificationManager.pendingIntent = intent diff --git a/goonj/src/main/java/ai/rever/goonj/manager/GoonjNotificationManager.kt b/goonj/src/main/java/ai/rever/goonj/manager/GoonjNotificationManager.kt index 13886a5..e45461c 100644 --- a/goonj/src/main/java/ai/rever/goonj/manager/GoonjNotificationManager.kt +++ b/goonj/src/main/java/ai/rever/goonj/manager/GoonjNotificationManager.kt @@ -2,7 +2,6 @@ package ai.rever.goonj.manager import ai.rever.goonj.Goonj import ai.rever.goonj.R -import ai.rever.goonj.models.defaultBitmap import ai.rever.goonj.util.PLAYBACK_CHANNEL_ID import ai.rever.goonj.util.PLAYBACK_NOTIFICATION_ID import android.app.Notification @@ -63,10 +62,13 @@ object GoonjNotificationManager { @Nullable override fun getCurrentLargeIcon(player: Player, callback: PlayerNotificationManager.BitmapCallback): Bitmap? { - // Todo load image from async using glide or picasso give to callback - - return Goonj.appContext?.defaultBitmap + val track = GoonjPlayerManager.trackList[player.currentWindowIndex] + track.load { + callback.onBitmap(it) + } + return track.bitmap } + } private val notificationListener = object : PlayerNotificationManager.NotificationListener { diff --git a/goonj/src/main/java/ai/rever/goonj/manager/GoonjPlayerManager.kt b/goonj/src/main/java/ai/rever/goonj/manager/GoonjPlayerManager.kt index baa3828..cb62fa7 100644 --- a/goonj/src/main/java/ai/rever/goonj/manager/GoonjPlayerManager.kt +++ b/goonj/src/main/java/ai/rever/goonj/manager/GoonjPlayerManager.kt @@ -54,7 +54,6 @@ internal object GoonjPlayerManager { internal fun addTrack(track: Track, index: Int = mTrackList.size) { track.trackState.index = index mTrackList.add(index, track) - player?.enqueue(track, index) } diff --git a/goonj/src/main/java/ai/rever/goonj/models/Track.kt b/goonj/src/main/java/ai/rever/goonj/models/Track.kt index 436dea5..64065e9 100644 --- a/goonj/src/main/java/ai/rever/goonj/models/Track.kt +++ b/goonj/src/main/java/ai/rever/goonj/models/Track.kt @@ -1,9 +1,11 @@ package ai.rever.goonj.models +import ai.rever.goonj.Goonj import ai.rever.goonj.Goonj.appContext import ai.rever.goonj.GoonjPlayerState import ai.rever.goonj.R import android.content.Context +import android.graphics.Bitmap import android.support.v4.media.MediaDescriptionCompat import android.support.v4.media.MediaMetadataCompat import android.os.Bundle @@ -11,7 +13,6 @@ import android.os.Parcelable import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap import androidx.core.net.toUri -import androidx.mediarouter.media.MediaItemStatus import androidx.room.Entity import androidx.room.Ignore import androidx.room.PrimaryKey @@ -85,6 +86,8 @@ data class Track (var url: String = "", @Ignore var extras: Bundle? = null, @Ignore + var bitmap: Bitmap? = null, + @Ignore val trackState: TrackState = TrackState() ): Parcelable { @@ -114,20 +117,49 @@ data class Track (var url: String = "", val mediaDescription: MediaDescriptionCompat get() { val extras = Bundle() + + val mediaDescriptionBuilder = MediaDescriptionCompat.Builder() .setMediaId(id) .setTitle(title) .setDescription(artistName) .setExtras(extras) - val bitmap = appContext?.defaultBitmap - extras.putParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap) - extras.putParcelable(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap) + if (bitmap != null) { + mediaDescriptionBuilder.setIconBitmap(bitmap) + + extras.putParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap) + extras.putParcelable(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, appContext?.defaultBitmap) - mediaDescriptionBuilder.setIconBitmap(bitmap) + } else { + val bitmap = appContext?.defaultBitmap + + extras.putParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap) + extras.putParcelable(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap) + + mediaDescriptionBuilder.setIconBitmap(bitmap) + } return mediaDescriptionBuilder.build() } + + fun load(callback: (Bitmap?) -> Unit) { + if (bitmap != null) { + callback(bitmap) + } + + val imageLoader = Goonj.imageLoader + if (imageLoader == null) { + bitmap = appContext?.defaultBitmap + callback(bitmap) + return + } + + imageLoader(this) { + bitmap = it + callback(it) + } + } } diff --git a/goonj/src/main/java/ai/rever/goonj/player/LocalAudioPlayer.kt b/goonj/src/main/java/ai/rever/goonj/player/LocalAudioPlayer.kt index eec8033..f343602 100644 --- a/goonj/src/main/java/ai/rever/goonj/player/LocalAudioPlayer.kt +++ b/goonj/src/main/java/ai/rever/goonj/player/LocalAudioPlayer.kt @@ -3,22 +3,27 @@ package ai.rever.goonj.player import ai.rever.goonj.Goonj.appContext import ai.rever.goonj.GoonjPlayerState import ai.rever.goonj.R -import ai.rever.goonj.analytics.* -import android.support.v4.media.MediaDescriptionCompat -import android.support.v4.media.session.MediaSessionCompat -import androidx.core.net.toUri +import ai.rever.goonj.analytics.ExoPlayerAnalyticsListenerImp +import ai.rever.goonj.analytics.ExoPlayerEvenListenerImp import ai.rever.goonj.download.DownloadUtil import ai.rever.goonj.interfaces.AudioPlayer -import ai.rever.goonj.models.Track import ai.rever.goonj.manager.GoonjNotificationManager.playerNotificationManager import ai.rever.goonj.manager.GoonjPlayerManager +import ai.rever.goonj.models.Track import ai.rever.goonj.util.MEDIA_SESSION_TAG +import android.support.v4.media.MediaDescriptionCompat +import android.support.v4.media.session.MediaSessionCompat import android.util.Log -import com.google.android.exoplayer2.* +import androidx.core.net.toUri +import com.google.android.exoplayer2.C +import com.google.android.exoplayer2.ExoPlayerFactory +import com.google.android.exoplayer2.Player +import com.google.android.exoplayer2.SimpleExoPlayer import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator -import com.google.android.exoplayer2.source.* +import com.google.android.exoplayer2.source.ConcatenatingMediaSource +import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory import com.google.android.exoplayer2.upstream.cache.CacheDataSource import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory @@ -27,6 +32,9 @@ import io.reactivex.Observable import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable import io.reactivex.rxkotlin.plusAssign +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import java.util.concurrent.TimeUnit class LocalAudioPlayer: AudioPlayer { @@ -133,7 +141,8 @@ class LocalAudioPlayer: AudioPlayer { } private fun updateCurrentlyPlayingTrack() { - val currentTrack = trackList[player.currentWindowIndex] + if (trackList.isEmpty()) return + val currentTrack = trackList[player.currentWindowIndex] val lastKnownTrack = GoonjPlayerManager.currentPlayingTrack.value if (player.contentDuration > 0) { @@ -219,8 +228,7 @@ class LocalAudioPlayer: AudioPlayer { } override fun enqueue(track: Track, index : Int) { - - val mediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory) + val mediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(track.url.toUri()) concatenatingMediaSource.addMediaSource(index, mediaSource)