From 3660a8bd78f5690620a33aa565b41492391da4d2 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 8 Jun 2022 23:17:15 +0530 Subject: [PATCH 1/4] Revert "[Playback] Code Cleanup" This reverts commit 7efbbc3f110935f8e5ee8bc9f6f35f6bb562d6ae. --- .../monkey/retromusic/service/CastPlayer.kt | 12 ++- .../retromusic/service/CrossFadePlayer.kt | 22 ++++-- .../retromusic/service/LocalPlayback.kt | 18 +++-- .../monkey/retromusic/service/MultiPlayer.kt | 50 +++++++----- .../monkey/retromusic/service/MusicService.kt | 76 ++++++++++--------- .../retromusic/service/PlaybackManager.kt | 10 ++- .../retromusic/service/playback/Playback.kt | 4 +- 7 files changed, 114 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt index e3404f24a..2a67051d6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt @@ -33,15 +33,19 @@ class CastPlayer(castSession: CastSession) : Playback, override var callbacks: Playback.PlaybackCallbacks? = null - override fun setDataSource(song: Song, force: Boolean): Boolean { - return try { + override fun setDataSource( + song: Song, + force: Boolean, + completion: (success: Boolean) -> Unit, + ) { + try { val mediaLoadOptions = MediaLoadOptions.Builder().setPlayPosition(0).setAutoplay(true).build() remoteMediaClient?.load(song.toMediaInfo()!!, mediaLoadOptions) - true + completion(true) } catch (e: Exception) { e.printStackTrace() - false + completion(false) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt index af9661feb..da27e6b36 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt @@ -120,17 +120,25 @@ class CrossFadePlayer(context: Context) : LocalPlayback(context) { override val isPlaying: Boolean get() = mIsInitialized && getCurrentPlayer()?.isPlaying == true - override fun setDataSource(song: Song, force: Boolean): Boolean { + override fun setDataSource( + song: Song, + force: Boolean, + completion: (success: Boolean) -> Unit, + ) { if (force) hasDataSource = false mIsInitialized = false /* We've already set DataSource if initialized is true in setNextDataSource */ - return if (!hasDataSource) { - mIsInitialized = setDataSourceImpl(getCurrentPlayer()!!, song.uri.toString()) + if (!hasDataSource) { + getCurrentPlayer()?.let { + setDataSourceImpl(it, song.uri.toString()) { success -> + mIsInitialized = success + completion(success) + } + } hasDataSource = true - mIsInitialized } else { + completion(true) mIsInitialized = true - true } } @@ -285,8 +293,8 @@ class CrossFadePlayer(context: Context) : LocalPlayback(context) { val nextSong = MusicPlayerRemote.nextSong // Switch to other player (Crossfade) only if next song exists if (nextSong != null) { - if (setDataSourceImpl(player, nextSong.uri.toString())) { - switchPlayer() + setDataSourceImpl(player, nextSong.uri.toString()) { success -> + if (success) switchPlayer() } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt b/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt index ee039f42c..fafbae0ec 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt @@ -109,10 +109,13 @@ abstract class LocalPlayback(val context: Context) : Playback, MediaPlayer.OnErr * @param path The path of the file, or the http/rtsp URL of the stream you want to play * @return True if the player has been prepared and is ready to play, false otherwise */ - fun setDataSourceImpl(player: MediaPlayer, path: String): Boolean { + fun setDataSourceImpl( + player: MediaPlayer, + path: String, + completion: (success: Boolean) -> Unit, + ) { + player.reset() try { - player.reset() - player.setOnPreparedListener(null) if (path.startsWith("content://")) { player.setDataSource(context, path.toUri()) } else { @@ -123,14 +126,17 @@ abstract class LocalPlayback(val context: Context) : Playback, MediaPlayer.OnErr .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build() ) - player.prepare() + player.setOnPreparedListener { + player.setOnPreparedListener(null) + completion(true) + } + player.prepareAsync() } catch (e: Exception) { + completion(false) e.printStackTrace() - return false } player.setOnCompletionListener(this) player.setOnErrorListener(this) - return true } private fun unregisterBecomingNoisyReceiver() { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt index d0e766b3f..8421b60f1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt @@ -46,13 +46,19 @@ class MultiPlayer(context: Context) : LocalPlayback(context) { * @param song The song object you want to play * @return True if the `player` has been prepared and is ready to play, false otherwise */ - override fun setDataSource(song: Song, force: Boolean): Boolean { + override fun setDataSource( + song: Song, + force: Boolean, + completion: (success: Boolean) -> Unit, + ) { isInitialized = false - isInitialized = setDataSourceImpl(mCurrentMediaPlayer, song.uri.toString()) - if (isInitialized) { - setNextDataSource(null) + setDataSourceImpl(mCurrentMediaPlayer, song.uri.toString()) { success -> + isInitialized = success + if (isInitialized) { + setNextDataSource(null) + } + completion(isInitialized) } - return isInitialized } /** @@ -80,26 +86,28 @@ class MultiPlayer(context: Context) : LocalPlayback(context) { mNextMediaPlayer = MediaPlayer() mNextMediaPlayer?.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) mNextMediaPlayer?.audioSessionId = audioSessionId - if (setDataSourceImpl(mNextMediaPlayer!!, path)) { - try { - mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer) - } catch (e: IllegalArgumentException) { - Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) + setDataSourceImpl(mNextMediaPlayer!!, path) { success -> + if (success) { + try { + mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer) + } catch (e: IllegalArgumentException) { + Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) + if (mNextMediaPlayer != null) { + mNextMediaPlayer?.release() + mNextMediaPlayer = null + } + } catch (e: IllegalStateException) { + Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) + if (mNextMediaPlayer != null) { + mNextMediaPlayer?.release() + mNextMediaPlayer = null + } + } + } else { if (mNextMediaPlayer != null) { mNextMediaPlayer?.release() mNextMediaPlayer = null } - } catch (e: IllegalStateException) { - Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) - if (mNextMediaPlayer != null) { - mNextMediaPlayer?.release() - mNextMediaPlayer = null - } - } - } else { - if (mNextMediaPlayer != null) { - mNextMediaPlayer?.release() - mNextMediaPlayer = null } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index cee0a47ed..512cd3839 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -117,11 +117,6 @@ class MusicService : MediaBrowserServiceCompat(), private var trackEndedByCrossfade = false private val serviceScope = CoroutineScope(Job() + Main) - // Every chromecast method needs to run on main thread or you are greeted with IllegalStateException - // So it will use Main dispatcher - // And by using Default dispatcher for local playback we are reducing the burden from main thread - private val playerDispatcher get() = if (playbackManager.isLocalPlayback) Default else Main - @JvmField var position = -1 private val appWidgetBig = AppWidgetBig.instance @@ -441,8 +436,11 @@ class MusicService : MediaBrowserServiceCompat(), } private fun setPosition(position: Int) { - openTrackAndPrepareNextAt(position) - notifyChange(PLAY_STATE_CHANGED) + openTrackAndPrepareNextAt(position) { success -> + if (success) { + notifyChange(PLAY_STATE_CHANGED) + } + } } private fun getPreviousPosition(force: Boolean): Int { @@ -757,15 +755,16 @@ class MusicService : MediaBrowserServiceCompat(), } @Synchronized - fun openTrackAndPrepareNextAt(position: Int): Boolean { + fun openTrackAndPrepareNextAt(position: Int, completion: (success: Boolean) -> Unit) { this.position = position - val prepared = openCurrent() - if (prepared) { - prepareNextImpl() + openCurrent { success -> + completion(success) + notifyChange(META_CHANGED) + notHandledMetaChangedForCurrentTrack = false + if (success) { + prepareNextImpl() + } } - notifyChange(META_CHANGED) - notHandledMetaChangedForCurrentTrack = false - return prepared } fun pause(force: Boolean = false) { @@ -794,11 +793,16 @@ class MusicService : MediaBrowserServiceCompat(), } fun playSongAt(position: Int) { - serviceScope.launch(playerDispatcher) { - if (openTrackAndPrepareNextAt(position)) { - play() - } else { - showToast(R.string.unplayable_file) + // Every chromecast method needs to run on main thread or you are greeted with IllegalStateException + // So it will use Main dispatcher + // And by using Default dispatcher for local playback we are reduce the burden of main thread + serviceScope.launch(if(playbackManager.isLocalPlayback) Default else Main) { + openTrackAndPrepareNextAt(position) { success -> + if (success) { + play() + } else { + showToast(resources.getString(R.string.unplayable_file)) + } } } } @@ -913,14 +917,15 @@ class MusicService : MediaBrowserServiceCompat(), originalPlayingQueue = ArrayList(restoredOriginalQueue) playingQueue = ArrayList(restoredQueue) position = restoredPosition - withContext(playerDispatcher) { - openCurrent() - prepareNext() - if (restoredPositionInTrack > 0) { - seek(restoredPositionInTrack) + withContext(Main) { + openCurrent { + prepareNext() + if (restoredPositionInTrack > 0) { + seek(restoredPositionInTrack) + } + notHandledMetaChangedForCurrentTrack = true + sendChangeInternal(META_CHANGED) } - notHandledMetaChangedForCurrentTrack = true - sendChangeInternal(META_CHANGED) if (receivedHeadsetConnected) { play() receivedHeadsetConnected = false @@ -1164,18 +1169,15 @@ class MusicService : MediaBrowserServiceCompat(), } @Synchronized - private fun openCurrent(): Boolean { + private fun openCurrent(completion: (success: Boolean) -> Unit) { val force = if (!trackEndedByCrossfade) { true } else { trackEndedByCrossfade = false false } - return try { - playbackManager.setDataSource(currentSong, force) - } catch (e: Exception) { - e.printStackTrace() - false + playbackManager.setDataSource(currentSong, force) { success -> + completion(success) } } @@ -1189,10 +1191,12 @@ class MusicService : MediaBrowserServiceCompat(), private fun restorePlaybackState(wasPlaying: Boolean, progress: Int) { playbackManager.setCallbacks(this) - if (openTrackAndPrepareNextAt(position)) { - seek(progress) - if (wasPlaying) { - play() + openTrackAndPrepareNextAt(position) { success -> + if (success) { + seek(progress) + if (wasPlaying) { + play() + } } } playbackManager.setCrossFadeDuration(crossFadeDuration) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt b/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt index f64b7d600..9186bd534 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt @@ -16,7 +16,7 @@ class PlaybackManager(val context: Context) { var playback: Playback? = null private var playbackLocation = PlaybackLocation.LOCAL - val isLocalPlayback get() = playbackLocation == PlaybackLocation.LOCAL + val isLocalPlayback get() = playbackLocation== PlaybackLocation.LOCAL val audioSessionId: Int get() = if (playback != null) { @@ -86,8 +86,12 @@ class PlaybackManager(val context: Context) { fun seek(millis: Int): Int = playback!!.seek(millis) - fun setDataSource(song: Song, force: Boolean): Boolean { - return playback?.setDataSource(song, force) == true + fun setDataSource( + song: Song, + force: Boolean, + completion: (success: Boolean) -> Unit, + ) { + playback?.setDataSource(song, force, completion) } fun setNextDataSource(trackUri: String) { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt index f3521ab96..3795e7634 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt @@ -25,7 +25,9 @@ interface Playback { val audioSessionId: Int - fun setDataSource(song: Song, force: Boolean):Boolean + fun setDataSource( + song: Song, force: Boolean, completion: (success: Boolean) -> Unit, + ) fun setNextDataSource(path: String?) From ceec034a4ffdd06426c2ba4fea14c2c7eac5efa0 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 8 Jun 2022 23:20:43 +0530 Subject: [PATCH 2/4] Revert "Start audio fade animator on Main thread" This reverts commit 46f713e6884be08e00541e4fa0646cb2f6cb5a12. --- .../java/code/name/monkey/retromusic/service/AudioFader.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/AudioFader.kt b/app/src/main/java/code/name/monkey/retromusic/service/AudioFader.kt index d79df4e43..009b0c40d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/AudioFader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/AudioFader.kt @@ -3,8 +3,6 @@ package code.name.monkey.retromusic.service import android.animation.Animator import android.animation.ValueAnimator import android.media.MediaPlayer -import android.os.Handler -import android.os.Looper import androidx.core.animation.doOnEnd import code.name.monkey.retromusic.service.playback.Playback import code.name.monkey.retromusic.util.PreferenceUtil @@ -59,9 +57,7 @@ class AudioFader { animator.doOnEnd { callback.run() } - Handler(Looper.getMainLooper()).post { - animator.start() - } + animator.start() } } } \ No newline at end of file From 75a4648e13a6053d20bdf899f358f1e9a1195384 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Thu, 9 Jun 2022 01:06:56 +0530 Subject: [PATCH 3/4] Fixed CrossFade duration not changing instantly --- .../retromusic/fragments/other/LyricsFragment.kt | 15 +-------------- .../monkey/retromusic/service/MusicService.kt | 2 ++ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt index 8dbaab6a7..e2eaf6c9b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt @@ -77,14 +77,6 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { baseUrl += query return baseUrl } - private val syairSearchLrcUrl: String - get() { - var baseUrl = "https://www.syair.info/search?" - var query = song.title + "+" + song.artistName - query = "q=" + query.replace(" ", "+") - baseUrl += query - return baseUrl - } private lateinit var normalLyricsLauncher: ActivityResultLauncher private lateinit var newSyncedLyricsLauncher: ActivityResultLauncher @@ -201,12 +193,7 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { override fun onMenuItemSelected(item: MenuItem): Boolean { if (item.itemId == R.id.action_search) { - openUrl(when (binding.lyricsPager.currentItem) { - 0 -> syairSearchLrcUrl - 1 -> googleSearchLrcUrl - else -> googleSearchLrcUrl - } - ) + openUrl(googleSearchLrcUrl) } return false } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index 512cd3839..16a550136 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -632,6 +632,8 @@ class MusicService : MediaBrowserServiceCompat(), if (playbackManager.maybeSwitchToCrossFade(crossFadeDuration)) { restorePlaybackState(wasPlaying, progress) + } else { + playbackManager.setCrossFadeDuration(crossFadeDuration) } } ALBUM_ART_ON_LOCK_SCREEN, BLURRED_ALBUM_ART -> updateMediaSessionMetaData(::updateMediaSessionPlaybackState) From bca9fb0b5a72946e4c1ef76e8d70d11b6ea58a12 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Thu, 9 Jun 2022 14:36:31 +0530 Subject: [PATCH 4/4] Fixed some landscape layouts --- app/build.gradle | 5 +- .../layout-land/fragment_adaptive_player.xml | 72 +++++++++++++++++++ .../layout-land/fragment_circle_player.xml | 14 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/layout-land/fragment_adaptive_player.xml diff --git a/app/build.gradle b/app/build.gradle index e203f7ea1..242402243 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,7 +14,7 @@ android { vectorDrawables.useSupportLibrary = true applicationId "code.name.monkey.retromusic" - versionCode 10590 + versionCode 10591 versionName '6.0.0-beta' buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") @@ -125,7 +125,7 @@ dependencies { def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" - implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.7' + implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.8' def material_dialog_version = "3.3.0" implementation "com.afollestad.material-dialogs:core:$material_dialog_version" @@ -167,5 +167,4 @@ dependencies { implementation 'me.zhanghai.android.fastscroll:library:1.1.8' implementation 'cat.ereza:customactivityoncrash:2.4.0' implementation 'me.tankery.lib:circularSeekBar:1.4.0' - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' } \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_adaptive_player.xml b/app/src/main/res/layout-land/fragment_adaptive_player.xml new file mode 100644 index 000000000..6a193abcb --- /dev/null +++ b/app/src/main/res/layout-land/fragment_adaptive_player.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_circle_player.xml b/app/src/main/res/layout-land/fragment_circle_player.xml index 71f388878..d1e87ac7f 100644 --- a/app/src/main/res/layout-land/fragment_circle_player.xml +++ b/app/src/main/res/layout-land/fragment_circle_player.xml @@ -112,7 +112,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" + android:background="?attr/roundSelector" android:padding="16dp" + android:scaleType="fitCenter" app:layout_constraintBottom_toBottomOf="@+id/playPauseButton" app:layout_constraintStart_toEndOf="@+id/playPauseButton" app:layout_constraintTop_toTopOf="@+id/playPauseButton" @@ -124,7 +126,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" + android:background="?attr/roundSelector" android:padding="16dp" + android:scaleType="fitCenter" app:layout_constraintBottom_toBottomOf="@+id/playPauseButton" app:layout_constraintEnd_toStartOf="@+id/playPauseButton" app:layout_constraintTop_toTopOf="@+id/playPauseButton" @@ -195,7 +199,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" - android:gravity="center_vertical|right|end" + android:gravity="center_vertical|end" android:singleLine="true" android:textColor="?android:attr/textColorSecondary" android:textSize="12sp" @@ -209,9 +213,11 @@ android:id="@+id/songCurrentProgress" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:gravity="center_vertical|left|end" - android:paddingLeft="8dp" + android:layout_alignParentStart="true" + android:layout_marginStart="16dp" + android:gravity="center_vertical|start" + android:paddingStart="8dp" + android:paddingEnd="0dp" android:singleLine="true" android:textColor="?android:attr/textColorSecondary" android:textSize="12sp" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6308cc5cc..20c531b95 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip