Skip to content
Open
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
17 changes: 7 additions & 10 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,24 +81,21 @@
</intent-filter>
</activity>

<!-- Media Browser Service for Android Auto -->
<!-- audio_service: media browser service used by Android Auto and
the media notification. Hosts a headless Flutter engine when the
car connects while the app UI is closed. -->
<service
android:name=".MusicService"
android:name="com.ryanheise.audioservice.AudioService"
android:exported="true"
android:enabled="true"
android:stopWithTask="false"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
<meta-data
android:name="android.media.browse.SEARCH_SUPPORTED"
android:value="true"/>
</service>
<!-- Media Button Receiver -->

<!-- audio_service media button receiver -->
<receiver
android:name="androidx.media.session.MediaButtonReceiver"
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
Expand Down
232 changes: 0 additions & 232 deletions android/app/src/main/kotlin/com/musly/musly/AndroidAutoPlugin.kt

This file was deleted.

78 changes: 35 additions & 43 deletions android/app/src/main/kotlin/com/musly/musly/AndroidSystemPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,28 +115,8 @@ object AndroidSystemPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
result.success(null)
}
"updatePlaybackState" -> {
val songId = call.argument<String>("songId")
val title = call.argument<String>("title") ?: ""
val artist = call.argument<String>("artist") ?: ""
val album = call.argument<String>("album") ?: ""
val artworkUrl = call.argument<String>("artworkUrl")
val duration = call.argument<Number>("duration")?.toLong() ?: 0L
val position = call.argument<Number>("position")?.toLong() ?: 0L
val playing = call.argument<Boolean>("playing") ?: false

// Ensure the service is running before updating state
val pushState = {
MusicService.getInstance()?.updatePlaybackState(
songId, title, artist, album, artworkUrl, duration, position, playing
)
}
if (MusicService.getInstance() == null) {
Log.d(TAG, "MusicService not running, requesting start via AndroidAutoPlugin")
AndroidAutoPlugin.startMusicService()
handler.postDelayed({ pushState() }, 200)
} else {
pushState()
}
// Media session metadata/state is now handled by audio_service
// (MuslyAudioHandler); nothing to do on this channel anymore.
result.success(null)
}
"setNotificationColor" -> {
Expand Down Expand Up @@ -167,17 +147,6 @@ object AndroidSystemPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
"getAndroidSdkVersion" -> {
result.success(Build.VERSION.SDK_INT)
}
"setRemotePlayback" -> {
val isRemote = call.argument<Boolean>("isRemote") ?: false
val volume = call.argument<Int>("volume") ?: 50
MusicService.getInstance()?.setRemoteVolume(isRemote, volume)
result.success(null)
}
"updateRemoteVolume" -> {
val volume = call.argument<Int>("volume") ?: 50
MusicService.getInstance()?.updateRemoteVolume(volume)
result.success(null)
}
"dispose" -> {
dispose()
result.success(null)
Expand All @@ -199,26 +168,49 @@ object AndroidSystemPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
Log.d(TAG, "AndroidSystemPlugin initialized")
}

private fun requestAudioFocus(): Boolean {
if (!handleAudioFocus) return true

val am = audioManager ?: return false

/**
* Returns "granted", "delayed", or "failed". "delayed" means the OS will
* asynchronously deliver AUDIOFOCUS_GAIN via [audioFocusListener] once the
* current focus holder yields (common on Android Auto / automotive audio
* routing, which is why [setAcceptsDelayedFocusGain] is set below).
*/
private fun requestAudioFocus(): String {
if (!handleAudioFocus) {
hasAudioFocus = true
return "granted"
}

val am = audioManager ?: return "failed"

return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()

audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(audioAttributes)
.setAcceptsDelayedFocusGain(true)
.setOnAudioFocusChangeListener(audioFocusListener, handler)
.build()

val result = am.requestAudioFocus(audioFocusRequest!!)
hasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
hasAudioFocus
when (result) {
AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
hasAudioFocus = true
"granted"
}
AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
// Keep audioFocusRequest/listener registered — the deferred
// AUDIOFOCUS_GAIN will arrive later through audioFocusListener.
hasAudioFocus = false
"delayed"
}
else -> {
hasAudioFocus = false
"failed"
}
}
} else {
@Suppress("DEPRECATION")
val result = am.requestAudioFocus(
Expand All @@ -227,7 +219,7 @@ object AndroidSystemPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
AudioManager.AUDIOFOCUS_GAIN
)
hasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
hasAudioFocus
if (hasAudioFocus) "granted" else "failed"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,6 @@ class BluetoothMediaHelper(private val context: Context) {
currentPosition = position
isPlaying = playing

MusicService.getInstance()?.apply {
updatePlaybackState(songId, title, artist, album, artworkUrl, duration, position, playing)
}

artworkUrl?.let { url ->
loadArtworkAsync(url)
}
Expand Down
Loading