feat(player): add Mornye media notification controls

Sync notification favorites with Library, add Mornye transport icons and an output action on legacy Android, and expose the iOS favorite command. Preserve playback position when controls refresh.

Vendor audio_service 0.18.19 with a small Android patch for custom notification actions. Modern Android keeps its system output switcher and transport layout.
This commit is contained in:
zarzet
2026-09-26 03:07:38 +07:00
parent 728d179d69
commit 5259c86365
80 changed files with 8973 additions and 13 deletions
+5
View File
@@ -35,6 +35,11 @@
android:networkSecurityConfig="@xml/network_security_config"
android:enableOnBackInvokedCallback="true"
android:localeConfig="@xml/locale_config">
<activity
android:name=".AudioOutputActivity"
android:exported="false"
android:excludeFromRecents="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity
android:name=".MainActivity"
android:exported="true"
@@ -0,0 +1,39 @@
package com.zarz.spotiflac
import android.app.Activity
import android.content.Intent
import android.media.MediaRouter2
import android.os.Build
import android.provider.Settings
/** A notification launches this activity directly, so output selection has a
* visible foreground context even while the Flutter player is in the background.
*/
class AudioOutputActivity : Activity() {
private var opened = false
private var pickerTookFocus = false
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (!hasFocus) {
if (opened) pickerTookFocus = true
return
}
if (opened) {
if (pickerTookFocus) finish()
return
}
opened = true
try {
if (Build.VERSION.SDK_INT >= 34 &&
MediaRouter2.getInstance(this).showSystemOutputSwitcher()) {
return
}
// Public output-switcher API is unavailable on older Android.
startActivity(Intent(Settings.ACTION_BLUETOOTH_SETTINGS))
} catch (_: Exception) {
// Do not leave a transparent activity over the notification shade.
}
finish()
}
}
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="#00000000" android:strokeColor="#FFFFFF"
android:strokeWidth="1.65" android:strokeLineCap="round"
android:pathData="M5.3,17.2 A9,9 0,1 1,18.7 17.2 M7.6,14.8 A5.8,5.8 0,1 1,16.4 14.8 M9.8,12.4 A2.65,2.65 0,1 1,14.2 12.4" />
<path android:fillColor="#FFFFFF"
android:pathData="M12,12.8 L17,21.5 L7,21.5 Z" />
</vector>
@@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="#00000000" android:strokeColor="#FFFFFF"
android:strokeWidth="1.7" android:strokeLineJoin="round"
android:pathData="M12,2.5 L14.85,8.6 L21.5,9.4 L16.6,14 L17.9,20.7 L12,17.3 L6.1,20.7 L7.4,14 L2.5,9.4 L9.15,8.6 Z" />
</vector>
@@ -0,0 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="#FFFFFF"
android:pathData="M12,2.5 L14.85,8.6 L21.5,9.4 L16.6,14 L17.9,20.7 L12,17.3 L6.1,20.7 L7.4,14 L2.5,9.4 L9.15,8.6 Z" />
</vector>
@@ -0,0 +1,2 @@
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/ic_notification_*,@drawable/ic_widget_previous,@drawable/ic_widget_next,@drawable/ic_widget_play,@drawable/ic_widget_pause" />