diff --git a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt index b2409a0..ea4b393 100644 --- a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt +++ b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt @@ -169,8 +169,12 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM return } + val bundledData = Arguments.toBundle(data) + val androidOptions = bundledData?.getBundle(MusicService.ANDROID_OPTIONS_KEY) + val allowBackgroundSetup = androidOptions?.getBoolean("allowBackgroundSetup") ?: false + // prevent crash Fatal Exception: android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && AppForegroundTracker.backgrounded) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && AppForegroundTracker.backgrounded && !allowBackgroundSetup) { promise.reject( "android_cannot_setup_player_in_background", "On Android the app must be in the foreground when setting up the player." @@ -179,7 +183,6 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } // Validate buffer keys. - val bundledData = Arguments.toBundle(data) val minBuffer = bundledData?.getDouble(MusicService.MIN_BUFFER_KEY)?.toMilliseconds()?.toInt() ?: DEFAULT_MIN_BUFFER_MS @@ -251,7 +254,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun updateOptions(data: ReadableMap?, callback: Promise) = scope.launch { + fun updateOptions(data: ReadableMap?, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch val options = Arguments.toBundle(data) @@ -262,9 +265,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } + } @ReactMethod - fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = scope.launch { + fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch try { @@ -283,9 +287,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM rejectWithException(callback, exception) } } + } @ReactMethod - fun load(data: ReadableMap?, callback: Promise) = scope.launch { + fun load(data: ReadableMap?, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch if (data == null) { callback.resolve(null) @@ -299,16 +304,18 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.reject("invalid_track_object", "Track was not a dictionary type") } } + } @ReactMethod - fun move(fromIndex: Int, toIndex: Int, callback: Promise) = scope.launch { + fun move(fromIndex: Int, toIndex: Int, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.move(fromIndex, toIndex) callback.resolve(null) } + } @ReactMethod - fun remove(data: ReadableArray?, callback: Promise) = scope.launch { + fun remove(data: ReadableArray?, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch val inputIndexes = Arguments.toList(data) if (inputIndexes != null) { @@ -329,9 +336,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } callback.resolve(null) } + } @ReactMethod - fun updateMetadataForTrack(index: Int, map: ReadableMap?, callback: Promise) = + fun updateMetadataForTrack(index: Int, map: ReadableMap?, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch @@ -346,9 +354,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } } + } @ReactMethod - fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = scope.launch { + fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch if (musicService.tracks.isEmpty()) @@ -362,9 +371,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } + } @ReactMethod - fun clearNowPlayingMetadata(callback: Promise) = scope.launch { + fun clearNowPlayingMetadata(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch if (musicService.tracks.isEmpty()) @@ -373,17 +383,19 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM musicService.clearNotificationMetadata() callback.resolve(null) } + } @ReactMethod - fun removeUpcomingTracks(callback: Promise) = scope.launch { + fun removeUpcomingTracks(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.removeUpcomingTracks() callback.resolve(null) } + } @ReactMethod - fun skip(index: Int, initialTime: Float, callback: Promise) = scope.launch { + fun skip(index: Int, initialTime: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.skip(index) @@ -394,9 +406,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } + } @ReactMethod - fun skipToNext(initialTime: Float, callback: Promise) = scope.launch { + fun skipToNext(initialTime: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.skipToNext() @@ -407,9 +420,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } + } @ReactMethod - fun skipToPrevious(initialTime: Float, callback: Promise) = scope.launch { + fun skipToPrevious(initialTime: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.skipToPrevious() @@ -420,9 +434,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } + } @ReactMethod - fun reset(callback: Promise) = scope.launch { + fun reset(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.stop() @@ -431,135 +446,152 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM callback.resolve(null) } + } @ReactMethod - fun play(callback: Promise) = scope.launch { + fun play(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.play() callback.resolve(null) } + } @ReactMethod - fun pause(callback: Promise) = scope.launch { + fun pause(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.pause() callback.resolve(null) } + } @ReactMethod - fun stop(callback: Promise) = scope.launch { + fun stop(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.stop() callback.resolve(null) } + } @ReactMethod - fun seekTo(seconds: Float, callback: Promise) = scope.launch { + fun seekTo(seconds: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.seekTo(seconds) callback.resolve(null) } + } @ReactMethod - fun seekBy(offset: Float, callback: Promise) = scope.launch { + fun seekBy(offset: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.seekBy(offset) callback.resolve(null) } + } @ReactMethod - fun retry(callback: Promise) = scope.launch { + fun retry(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.retry() callback.resolve(null) } + } @ReactMethod - fun setVolume(volume: Float, callback: Promise) = scope.launch { + fun setVolume(volume: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.setVolume(volume) callback.resolve(null) } + } @ReactMethod - fun getVolume(callback: Promise) = scope.launch { + fun getVolume(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.getVolume()) } + } @ReactMethod - fun setRate(rate: Float, callback: Promise) = scope.launch { + fun setRate(rate: Float, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.setRate(rate) callback.resolve(null) } + } @ReactMethod - fun getRate(callback: Promise) = scope.launch { + fun getRate(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.getRate()) } + } @ReactMethod - fun setRepeatMode(mode: Int, callback: Promise) = scope.launch { + fun setRepeatMode(mode: Int, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.setRepeatMode(RepeatMode.fromOrdinal(mode)) callback.resolve(null) } + } @ReactMethod - fun getRepeatMode(callback: Promise) = scope.launch { + fun getRepeatMode(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.getRepeatMode().ordinal) } + } @ReactMethod - fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = scope.launch { + fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch musicService.playWhenReady = playWhenReady callback.resolve(null) } + } @ReactMethod - fun getPlayWhenReady(callback: Promise) = scope.launch { + fun getPlayWhenReady(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.playWhenReady) } + } @ReactMethod - fun getTrack(index: Int, callback: Promise) = scope.launch { + fun getTrack(index: Int, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch if (index >= 0 && index < musicService.tracks.size) { - callback.resolve(Arguments.fromBundle(musicService.tracks[index].originalItem)) + callback.resolve(musicService.tracks[index].originalItem?.let { Arguments.fromBundle(it) }) } else { callback.resolve(null) } } + } @ReactMethod - fun getQueue(callback: Promise) = scope.launch { + fun getQueue(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(Arguments.fromList(musicService.tracks.map { it.originalItem })) } + } @ReactMethod - fun setQueue(data: ReadableArray?, callback: Promise) = scope.launch { + fun setQueue(data: ReadableArray?, callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch try { @@ -570,49 +602,54 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM rejectWithException(callback, exception) } } + } @ReactMethod - fun getActiveTrackIndex(callback: Promise) = scope.launch { + fun getActiveTrackIndex(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve( if (musicService.tracks.isEmpty()) null else musicService.getCurrentTrackIndex() ) } + } @ReactMethod - fun getActiveTrack(callback: Promise) = scope.launch { + fun getActiveTrack(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve( if (musicService.tracks.isEmpty()) null - else Arguments.fromBundle( - musicService.tracks[musicService.getCurrentTrackIndex()].originalItem - ) + else musicService.tracks[musicService.getCurrentTrackIndex()].originalItem + ?.let { Arguments.fromBundle(it) } ) } + } @ReactMethod - fun getDuration(callback: Promise) = scope.launch { + fun getDuration(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.getDurationInSeconds()) } + } @ReactMethod - fun getBufferedPosition(callback: Promise) = scope.launch { + fun getBufferedPosition(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.getBufferedPositionInSeconds()) } + } @ReactMethod - fun getPosition(callback: Promise) = scope.launch { + fun getPosition(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(musicService.getPositionInSeconds()) } + } @ReactMethod - fun getProgress(callback: Promise) = scope.launch { + fun getProgress(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch var bundle = Bundle() bundle.putDouble("duration", musicService.getDurationInSeconds()); @@ -620,10 +657,12 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM bundle.putDouble("buffered", musicService.getBufferedPositionInSeconds()); callback.resolve(Arguments.fromBundle(bundle)) } + } @ReactMethod - fun getPlaybackState(callback: Promise) = scope.launch { + fun getPlaybackState(callback: Promise) { scope.launch { if (verifyServiceBoundOrReject(callback)) return@launch callback.resolve(Arguments.fromBundle(musicService.getPlayerStateBundle(musicService.state))) } + } } diff --git a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt index afa6b0f..c6f01d5 100644 --- a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt +++ b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt @@ -741,7 +741,7 @@ class MusicService : HeadlessJsTaskService() { @MainThread private fun emit(event: String, data: Bundle? = null) { - reactNativeHost.reactInstanceManager.currentReactContext + (applicationContext as? com.facebook.react.ReactApplication)?.reactHost?.currentReactContext ?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) ?.emit(event, data?.let { Arguments.fromBundle(it) }) } @@ -751,7 +751,7 @@ class MusicService : HeadlessJsTaskService() { val payload = Arguments.createArray() data.forEach { payload.pushMap(Arguments.fromBundle(it)) } - reactNativeHost.reactInstanceManager.currentReactContext + (applicationContext as? com.facebook.react.ReactApplication)?.reactHost?.currentReactContext ?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) ?.emit(event, payload) }