@javascriptcommon/react-native-track-player 1.2.9 → 1.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +61 -4
- package/android/src/main/AndroidManifest.xml +2 -4
- package/android/src/main/ic_home-playstore.png +0 -0
- package/android/src/main/ic_repeat-playstore.png +0 -0
- package/android/src/main/ic_repeat_50-playstore.png +0 -0
- package/android/src/main/ic_shuffle-playstore.png +0 -0
- package/android/src/main/ic_shuffle_50-playstore.png +0 -0
- package/android/src/main/ic_shuffle_sm-playstore.png +0 -0
- package/android/src/main/ic_stop-playstore.png +0 -0
- package/android/src/main/ic_test-playstore.png +0 -0
- package/android/src/main/java/com/guichaguri/trackplayer/{service/HeadlessJsMediaService.java → HeadlessJsMediaService.java} +83 -32
- package/android/src/main/java/com/guichaguri/trackplayer/TrackPlayer.kt +25 -0
- package/android/src/main/java/com/guichaguri/trackplayer/extensions/AudioPlayerStateExt.kt +19 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/event/EventHolder.kt +30 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/event/NotificationEventHolder.kt +20 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/event/PlayerEventHolder.kt +111 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AAMediaSessionCallback.kt +10 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioContentType.kt +10 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioItem.kt +66 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioItemTransitionReason.kt +33 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioPlayerState.kt +30 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/BufferConfig.kt +8 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/CacheConfig.kt +17 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/Capability.kt +19 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/FocusChangeData.kt +3 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/MediaSessionCallback.kt +17 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/NotificationConfig.kt +43 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/NotificationMetadata.kt +8 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/NotificationState.kt +8 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlayWhenReadyChangeData.kt +5 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlaybackEndedReason.kt +5 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlaybackError.kt +6 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlaybackMetadata.kt +200 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlayerConfig.kt +33 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlayerOptions.kt +9 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PositionChangedReason.kt +39 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/QueuedPlayerOptions.kt +49 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/notification/NotificationManager.kt +678 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/AudioPlayer.kt +10 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/BaseAudioPlayer.kt +864 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/QueuedAudioPlayer.kt +269 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/components/MediaSourceExt.kt +35 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/components/PlayerCache.kt +26 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/utils/Utils.kt +12 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/MetadataAdapter.kt +224 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/State.kt +13 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/Track.kt +120 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/TrackAudioItem.kt +19 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/TrackType.kt +11 -0
- package/android/src/main/java/com/guichaguri/trackplayer/module/AutoConnectionDetector.kt +151 -0
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicEvents.kt +66 -0
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicModule.kt +1192 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/BundleUtils.kt +117 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicBinder.kt +31 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicManager.kt +347 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicService.kt +1268 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/Utils.kt +228 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/ButtonEvents.kt +141 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/MetadataManager.kt +396 -0
- package/android/src/main/res/drawable-hdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-mdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-xhdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-xxhdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-xxxhdpi/ic_home.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/raw/silent_5_seconds.mp3 +0 -0
- package/android/src/main/res/strings.xml +6 -0
- package/android/src/main/res/values/strings.xml +6 -0
- package/index.d.ts +62 -1
- package/lib/index.js +10 -9
- package/package.json +1 -1
- package/android/src/main/java/com/guichaguri/trackplayer/TrackPlayer.java +0 -28
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicEvents.java +0 -55
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicModule.java +0 -298
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicBinder.java +0 -47
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicManager.java +0 -383
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicService.java +0 -271
- package/android/src/main/java/com/guichaguri/trackplayer/service/Utils.java +0 -243
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/ButtonEvents.java +0 -148
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/MetadataManager.java +0 -379
- package/android/src/main/java/com/guichaguri/trackplayer/service/models/Track.java +0 -141
- package/android/src/main/java/com/guichaguri/trackplayer/service/models/TrackType.java +0 -35
- package/android/src/main/res/drawable-hdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-mdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-xhdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-xxhdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-xxxhdpi/ic_logo.png +0 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.kotlinaudio.notification
|
|
2
|
+
|
|
3
|
+
import android.app.Notification
|
|
4
|
+
import android.app.PendingIntent
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.graphics.Bitmap
|
|
8
|
+
import android.graphics.BitmapFactory
|
|
9
|
+
import android.graphics.Color
|
|
10
|
+
import android.graphics.drawable.BitmapDrawable
|
|
11
|
+
import android.net.Uri
|
|
12
|
+
import android.os.Build
|
|
13
|
+
import android.os.Bundle
|
|
14
|
+
import android.support.v4.media.MediaDescriptionCompat
|
|
15
|
+
import android.support.v4.media.MediaMetadataCompat
|
|
16
|
+
import android.support.v4.media.session.MediaSessionCompat
|
|
17
|
+
import android.support.v4.media.session.PlaybackStateCompat
|
|
18
|
+
import android.util.Log
|
|
19
|
+
import androidx.annotation.DrawableRes
|
|
20
|
+
import androidx.core.app.NotificationCompat
|
|
21
|
+
import coil.imageLoader
|
|
22
|
+
import coil.request.Disposable
|
|
23
|
+
import coil.request.ImageRequest
|
|
24
|
+
import com.guichaguri.trackplayer.R
|
|
25
|
+
import com.guichaguri.trackplayer.kotlinaudio.event.NotificationEventHolder
|
|
26
|
+
import com.guichaguri.trackplayer.kotlinaudio.event.PlayerEventHolder
|
|
27
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.AudioItemHolder
|
|
28
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.MediaSessionCallback
|
|
29
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.NotificationButton
|
|
30
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.NotificationConfig
|
|
31
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.NotificationMetadata
|
|
32
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.NotificationState
|
|
33
|
+
import com.google.android.exoplayer2.Player
|
|
34
|
+
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
|
|
35
|
+
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
|
|
36
|
+
import com.google.android.exoplayer2.ui.PlayerNotificationManager
|
|
37
|
+
import com.google.android.exoplayer2.ui.PlayerNotificationManager.CustomActionReceiver
|
|
38
|
+
import kotlinx.coroutines.MainScope
|
|
39
|
+
import kotlinx.coroutines.launch
|
|
40
|
+
import java.io.File
|
|
41
|
+
import java.net.URI
|
|
42
|
+
|
|
43
|
+
class NotificationManager internal constructor(
|
|
44
|
+
private val context: Context,
|
|
45
|
+
private val player: Player,
|
|
46
|
+
private val mediaSession: MediaSessionCompat,
|
|
47
|
+
private val mediaSessionConnector: MediaSessionConnector,
|
|
48
|
+
val event: NotificationEventHolder,
|
|
49
|
+
val playerEventHolder: PlayerEventHolder
|
|
50
|
+
) : PlayerNotificationManager.NotificationListener {
|
|
51
|
+
private lateinit var descriptionAdapter: PlayerNotificationManager.MediaDescriptionAdapter
|
|
52
|
+
private var internalNotificationManager: PlayerNotificationManager? = null
|
|
53
|
+
private val scope = MainScope()
|
|
54
|
+
private val buttons = mutableSetOf<NotificationButton?>()
|
|
55
|
+
private var notificationMetadataArtworkDisposable: Disposable? = null
|
|
56
|
+
var notificationMetadata: NotificationMetadata? = null
|
|
57
|
+
set(value) {
|
|
58
|
+
// Clear bitmap cache if artwork changes
|
|
59
|
+
if (field?.artworkUrl != value?.artworkUrl) {
|
|
60
|
+
val holder = getCurrentItemHolder()
|
|
61
|
+
if (holder != null) {
|
|
62
|
+
holder.artworkBitmap = null
|
|
63
|
+
if (value?.artworkUrl != null) {
|
|
64
|
+
notificationMetadataArtworkDisposable?.dispose()
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
if (value.artworkUrl.startsWith("file")) {
|
|
68
|
+
val uri = URI(value.artworkUrl)
|
|
69
|
+
val sanitizedUri = URI(uri.scheme, null, uri.path, null, null)
|
|
70
|
+
if (sanitizedUri.query == null) {
|
|
71
|
+
val file = File(sanitizedUri)
|
|
72
|
+
if (file.exists()) {
|
|
73
|
+
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
|
|
74
|
+
holder.artworkBitmap = bitmap
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
notificationMetadataArtworkDisposable = context.imageLoader.enqueue(
|
|
79
|
+
ImageRequest.Builder(context)
|
|
80
|
+
.data(value.artworkUrl)
|
|
81
|
+
.target { result ->
|
|
82
|
+
val bitmap = (result as BitmapDrawable).bitmap
|
|
83
|
+
holder.artworkBitmap = bitmap
|
|
84
|
+
}
|
|
85
|
+
.build()
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
} catch (_: Exception) {}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
field = value
|
|
93
|
+
invalidate()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
var showPlayPauseButton = false
|
|
98
|
+
set(value) {
|
|
99
|
+
scope.launch {
|
|
100
|
+
field = value
|
|
101
|
+
internalNotificationManager?.setUsePlayPauseActions(value)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
var showStopButton = false
|
|
106
|
+
set(value) {
|
|
107
|
+
scope.launch {
|
|
108
|
+
field = value
|
|
109
|
+
internalNotificationManager?.setUseStopAction(value)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
var showForwardButton = false
|
|
114
|
+
set(value) {
|
|
115
|
+
scope.launch {
|
|
116
|
+
field = value
|
|
117
|
+
internalNotificationManager?.setUseFastForwardAction(value)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Controls whether or not this button should appear when the notification is compact (collapsed).
|
|
123
|
+
*/
|
|
124
|
+
var showForwardButtonCompact = false
|
|
125
|
+
set(value) {
|
|
126
|
+
scope.launch {
|
|
127
|
+
field = value
|
|
128
|
+
internalNotificationManager?.setUseFastForwardActionInCompactView(value)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var showRewindButton = false
|
|
133
|
+
set(value) {
|
|
134
|
+
scope.launch {
|
|
135
|
+
field = value
|
|
136
|
+
internalNotificationManager?.setUseRewindAction(value)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Controls whether or not this button should appear when the notification is compact (collapsed).
|
|
142
|
+
*/
|
|
143
|
+
var showRewindButtonCompact = false
|
|
144
|
+
set(value) {
|
|
145
|
+
scope.launch {
|
|
146
|
+
field = value
|
|
147
|
+
internalNotificationManager?.setUseRewindActionInCompactView(value)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
var showNextButton = false
|
|
152
|
+
set(value) {
|
|
153
|
+
scope.launch {
|
|
154
|
+
field = value
|
|
155
|
+
internalNotificationManager?.setUseNextAction(value)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Controls whether or not this button should appear when the notification is compact (collapsed).
|
|
161
|
+
*/
|
|
162
|
+
var showNextButtonCompact = false
|
|
163
|
+
set(value) {
|
|
164
|
+
scope.launch {
|
|
165
|
+
field = value
|
|
166
|
+
internalNotificationManager?.setUseNextActionInCompactView(value)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
var showPreviousButton = false
|
|
171
|
+
set(value) {
|
|
172
|
+
scope.launch {
|
|
173
|
+
field = value
|
|
174
|
+
internalNotificationManager?.setUsePreviousAction(value)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Controls whether or not this button should appear when the notification is compact (collapsed).
|
|
180
|
+
*/
|
|
181
|
+
var showPreviousButtonCompact = false
|
|
182
|
+
set(value) {
|
|
183
|
+
scope.launch {
|
|
184
|
+
field = value
|
|
185
|
+
internalNotificationManager?.setUsePreviousActionInCompactView(value)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
var stopIcon: Int? = null
|
|
190
|
+
var forwardIcon: Int? = null
|
|
191
|
+
var rewindIcon: Int? = null
|
|
192
|
+
var customIcons: MutableMap<String, Int?> = mutableMapOf()
|
|
193
|
+
|
|
194
|
+
private fun getCurrentItemHolder(): AudioItemHolder? {
|
|
195
|
+
return player?.currentMediaItem?.localConfiguration?.tag as AudioItemHolder?
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
init {
|
|
199
|
+
mediaSessionConnector.setQueueNavigator(
|
|
200
|
+
object : TimelineQueueNavigator(mediaSession) {
|
|
201
|
+
override fun getSupportedQueueNavigatorActions(player: Player): Long {
|
|
202
|
+
return buttons.fold(0) { acc, button ->
|
|
203
|
+
acc or when (button) {
|
|
204
|
+
is NotificationButton.NEXT -> {
|
|
205
|
+
PlaybackStateCompat.ACTION_SKIP_TO_NEXT
|
|
206
|
+
}
|
|
207
|
+
is NotificationButton.PREVIOUS -> {
|
|
208
|
+
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
|
|
209
|
+
}
|
|
210
|
+
else -> {
|
|
211
|
+
0
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
override fun getMediaDescription(
|
|
218
|
+
player: Player,
|
|
219
|
+
windowIndex: Int
|
|
220
|
+
): MediaDescriptionCompat {
|
|
221
|
+
val currentNotificationMetadata =
|
|
222
|
+
if (windowIndex == player.currentMediaItemIndex)
|
|
223
|
+
notificationMetadata else null
|
|
224
|
+
val mediaItem = player.getMediaItemAt(windowIndex)
|
|
225
|
+
val audioItemHolder = (mediaItem.localConfiguration?.tag as AudioItemHolder)
|
|
226
|
+
var title = currentNotificationMetadata?.title ?: mediaItem.mediaMetadata.title
|
|
227
|
+
?: audioItemHolder.audioItem.title
|
|
228
|
+
var artist =
|
|
229
|
+
currentNotificationMetadata?.artist ?: mediaItem.mediaMetadata.artist
|
|
230
|
+
?: audioItemHolder.audioItem.artist
|
|
231
|
+
return MediaDescriptionCompat.Builder().apply {
|
|
232
|
+
setTitle(title)
|
|
233
|
+
setSubtitle(artist)
|
|
234
|
+
setExtras(Bundle().apply {
|
|
235
|
+
putString(MediaMetadataCompat.METADATA_KEY_TITLE, title as String?)
|
|
236
|
+
putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist as String?)
|
|
237
|
+
})
|
|
238
|
+
setIconUri(mediaItem?.mediaMetadata?.artworkUri ?: Uri.parse(audioItemHolder?.audioItem?.artwork
|
|
239
|
+
?: ""))
|
|
240
|
+
setIconBitmap(audioItemHolder?.artworkBitmap)
|
|
241
|
+
}.build()
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
mediaSessionConnector.setMetadataDeduplicationEnabled(true)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
fun getMediaMetadataCompat(): MediaMetadataCompat {
|
|
249
|
+
return MediaMetadataCompat.Builder().apply {
|
|
250
|
+
val audioHolder = getCurrentItemHolder()
|
|
251
|
+
val mediaItem = audioHolder?.audioItem
|
|
252
|
+
val currentMediaMetadata = player.currentMediaItem?.mediaMetadata
|
|
253
|
+
putString(MediaMetadataCompat.METADATA_KEY_ARTIST, notificationMetadata?.artist?: mediaItem?.artist)
|
|
254
|
+
putString(MediaMetadataCompat.METADATA_KEY_TITLE, notificationMetadata?.title?: mediaItem?.title)
|
|
255
|
+
putString(MediaMetadataCompat.METADATA_KEY_ALBUM, mediaItem?.albumTitle)
|
|
256
|
+
putString(MediaMetadataCompat.METADATA_KEY_GENRE, currentMediaMetadata?.genre.toString())
|
|
257
|
+
putLong(MediaMetadataCompat.METADATA_KEY_DURATION, notificationMetadata?.duration ?: mediaItem?.duration?: player.duration)
|
|
258
|
+
|
|
259
|
+
if (audioHolder?.artworkBitmap != null) {
|
|
260
|
+
putBitmap(MediaMetadataCompat.METADATA_KEY_ART, audioHolder.artworkBitmap)
|
|
261
|
+
} else {
|
|
262
|
+
val artworkUrl = notificationMetadata?.artworkUrl ?: mediaItem?.artwork
|
|
263
|
+
if (artworkUrl != null) {
|
|
264
|
+
if (artworkUrl.startsWith("file")) {
|
|
265
|
+
try {
|
|
266
|
+
val uri = URI(artworkUrl)
|
|
267
|
+
val sanitizedUri = URI(uri.scheme, null, uri.path, null, null)
|
|
268
|
+
if (sanitizedUri.query == null) {
|
|
269
|
+
val file = File(sanitizedUri)
|
|
270
|
+
if (file.exists()) {
|
|
271
|
+
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
|
|
272
|
+
putBitmap(
|
|
273
|
+
MediaMetadataCompat.METADATA_KEY_ART,
|
|
274
|
+
bitmap
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} catch (_: Exception) {}
|
|
279
|
+
} else {
|
|
280
|
+
putString(
|
|
281
|
+
MediaMetadataCompat.METADATA_KEY_ART_URI,
|
|
282
|
+
artworkUrl
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}.build()
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private fun createNotificationAction(
|
|
291
|
+
drawable: Int,
|
|
292
|
+
action: String,
|
|
293
|
+
instanceId: Int
|
|
294
|
+
): NotificationCompat.Action {
|
|
295
|
+
val intent: Intent = Intent(action).setPackage(context.packageName)
|
|
296
|
+
val pendingIntent = PendingIntent.getBroadcast(
|
|
297
|
+
context,
|
|
298
|
+
instanceId,
|
|
299
|
+
intent,
|
|
300
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
301
|
+
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
|
|
302
|
+
} else {
|
|
303
|
+
PendingIntent.FLAG_CANCEL_CURRENT
|
|
304
|
+
}
|
|
305
|
+
)
|
|
306
|
+
return NotificationCompat.Action.Builder(drawable, action, pendingIntent).build()
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private fun handlePlayerAction(action: String) {
|
|
310
|
+
when (action) {
|
|
311
|
+
REWIND -> {
|
|
312
|
+
playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.REWIND)
|
|
313
|
+
}
|
|
314
|
+
FORWARD -> {
|
|
315
|
+
playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.FORWARD)
|
|
316
|
+
}
|
|
317
|
+
STOP -> {
|
|
318
|
+
playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.STOP)
|
|
319
|
+
}
|
|
320
|
+
else -> {
|
|
321
|
+
playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.CUSTOMACTION(action))
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private val customActionReceiver = object : CustomActionReceiver {
|
|
328
|
+
override fun createCustomActions(
|
|
329
|
+
context: Context,
|
|
330
|
+
instanceId: Int
|
|
331
|
+
): MutableMap<String, NotificationCompat.Action> {
|
|
332
|
+
if (!needsCustomActionsToAddMissingButtons) return mutableMapOf()
|
|
333
|
+
var actionMap: MutableMap<String, NotificationCompat.Action> = mutableMapOf()
|
|
334
|
+
// only use rewind/forward/stop mapping with android >13.
|
|
335
|
+
if (Build.VERSION.SDK_INT >= 33) {
|
|
336
|
+
actionMap = mutableMapOf(
|
|
337
|
+
REWIND to createNotificationAction(
|
|
338
|
+
rewindIcon ?: DEFAULT_REWIND_ICON,
|
|
339
|
+
REWIND,
|
|
340
|
+
instanceId
|
|
341
|
+
),
|
|
342
|
+
FORWARD to createNotificationAction(
|
|
343
|
+
forwardIcon ?: DEFAULT_FORWARD_ICON,
|
|
344
|
+
FORWARD,
|
|
345
|
+
instanceId
|
|
346
|
+
),
|
|
347
|
+
STOP to createNotificationAction(
|
|
348
|
+
stopIcon ?: DEFAULT_STOP_ICON,
|
|
349
|
+
STOP,
|
|
350
|
+
instanceId
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
customIcons.forEach { (key, value) ->
|
|
355
|
+
actionMap[key] = createNotificationAction(value?: DEFAULT_STOP_ICON, key, instanceId)
|
|
356
|
+
}
|
|
357
|
+
return actionMap
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
override fun getCustomActions(player: Player): List<String> {
|
|
361
|
+
if (!needsCustomActionsToAddMissingButtons) return emptyList()
|
|
362
|
+
return buttons.mapNotNull {
|
|
363
|
+
when (it) {
|
|
364
|
+
is NotificationButton.BACKWARD -> {
|
|
365
|
+
REWIND
|
|
366
|
+
}
|
|
367
|
+
is NotificationButton.FORWARD -> {
|
|
368
|
+
FORWARD
|
|
369
|
+
}
|
|
370
|
+
is NotificationButton.STOP -> {
|
|
371
|
+
STOP
|
|
372
|
+
}
|
|
373
|
+
is NotificationButton.CUSTOM_ACTION -> {
|
|
374
|
+
it.customAction
|
|
375
|
+
}
|
|
376
|
+
else -> {
|
|
377
|
+
null
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
override fun onCustomAction(player: Player, action: String, intent: Intent) {
|
|
384
|
+
handlePlayerAction(action)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
fun invalidate() {
|
|
389
|
+
internalNotificationManager?.invalidate()
|
|
390
|
+
mediaSessionConnector.invalidateMediaSessionQueue()
|
|
391
|
+
mediaSessionConnector.invalidateMediaSessionMetadata()
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Create a media player notification that automatically updates.
|
|
396
|
+
*
|
|
397
|
+
* **NOTE:** You should only call this once. Subsequent calls will result in an error.
|
|
398
|
+
*/
|
|
399
|
+
fun createNotification(config: NotificationConfig) = scope.launch {
|
|
400
|
+
buttons.apply {
|
|
401
|
+
clear()
|
|
402
|
+
addAll(config.buttons)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
stopIcon = null
|
|
406
|
+
forwardIcon = null
|
|
407
|
+
rewindIcon = null
|
|
408
|
+
mediaSessionConnector.setEnabledPlaybackActions(
|
|
409
|
+
buttons.fold(
|
|
410
|
+
PlaybackStateCompat.ACTION_SET_REPEAT_MODE
|
|
411
|
+
or PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
|
|
412
|
+
or PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED
|
|
413
|
+
) { acc, button ->
|
|
414
|
+
acc or when (button) {
|
|
415
|
+
is NotificationButton.PLAY_PAUSE -> {
|
|
416
|
+
PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE
|
|
417
|
+
}
|
|
418
|
+
is NotificationButton.PREVIOUS -> {
|
|
419
|
+
rewindIcon = button.icon ?: rewindIcon
|
|
420
|
+
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
|
|
421
|
+
}
|
|
422
|
+
is NotificationButton.NEXT -> {
|
|
423
|
+
forwardIcon = button.icon ?: forwardIcon
|
|
424
|
+
PlaybackStateCompat.ACTION_SKIP_TO_NEXT
|
|
425
|
+
}
|
|
426
|
+
is NotificationButton.SEEK_TO -> {
|
|
427
|
+
PlaybackStateCompat.ACTION_SEEK_TO
|
|
428
|
+
}
|
|
429
|
+
is NotificationButton.STOP -> {
|
|
430
|
+
stopIcon = button.icon ?: stopIcon
|
|
431
|
+
PlaybackStateCompat.ACTION_STOP
|
|
432
|
+
}
|
|
433
|
+
is NotificationButton.CUSTOM_ACTION -> {
|
|
434
|
+
stopIcon = button.icon ?: stopIcon
|
|
435
|
+
customIcons[button.customAction ?: "DEFAULT_CUSTOM"] = button.icon ?: stopIcon
|
|
436
|
+
PlaybackStateCompat.ACTION_SET_RATING
|
|
437
|
+
}
|
|
438
|
+
else -> {
|
|
439
|
+
0
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
)
|
|
444
|
+
descriptionAdapter = object : PlayerNotificationManager.MediaDescriptionAdapter {
|
|
445
|
+
override fun getCurrentContentTitle(player: Player): CharSequence {
|
|
446
|
+
return notificationMetadata?.title
|
|
447
|
+
?: player.mediaMetadata.title
|
|
448
|
+
?: ""
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
override fun createCurrentContentIntent(player: Player): PendingIntent? {
|
|
452
|
+
return config.pendingIntent
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
override fun getCurrentContentText(player: Player): CharSequence? {
|
|
456
|
+
return notificationMetadata?.artist
|
|
457
|
+
?: player.mediaMetadata.artist
|
|
458
|
+
?: player.mediaMetadata.albumArtist
|
|
459
|
+
?: ""
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
override fun getCurrentSubText(player: Player): CharSequence? {
|
|
463
|
+
return player.mediaMetadata.displayTitle
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
override fun getCurrentLargeIcon(
|
|
467
|
+
player: Player,
|
|
468
|
+
callback: PlayerNotificationManager.BitmapCallback,
|
|
469
|
+
): Bitmap? {
|
|
470
|
+
val holder = getCurrentItemHolder() ?: return null
|
|
471
|
+
val source = notificationMetadata?.artworkUrl ?: player.mediaMetadata.artworkUri
|
|
472
|
+
val data = player.mediaMetadata.artworkData
|
|
473
|
+
|
|
474
|
+
if (notificationMetadata?.artworkUrl == null && data != null) {
|
|
475
|
+
return BitmapFactory.decodeByteArray(data, 0, data.size)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (source == null) {
|
|
479
|
+
return null
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (holder.artworkBitmap != null) {
|
|
483
|
+
return holder.artworkBitmap
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
context.imageLoader.enqueue(
|
|
487
|
+
ImageRequest.Builder(context)
|
|
488
|
+
.data(source)
|
|
489
|
+
.target { result ->
|
|
490
|
+
val bitmap = (result as BitmapDrawable).bitmap
|
|
491
|
+
holder.artworkBitmap = bitmap
|
|
492
|
+
callback.onBitmap(bitmap)
|
|
493
|
+
}
|
|
494
|
+
.build()
|
|
495
|
+
)
|
|
496
|
+
return holder.artworkBitmap
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (needsCustomActionsToAddMissingButtons) {
|
|
501
|
+
val customActionProviders = buttons
|
|
502
|
+
// .sortedBy {
|
|
503
|
+
// when (it) {
|
|
504
|
+
// is NotificationButton.BACKWARD -> 1
|
|
505
|
+
// is NotificationButton.FORWARD -> 2
|
|
506
|
+
// is NotificationButton.STOP -> 3
|
|
507
|
+
// else -> 4
|
|
508
|
+
// }
|
|
509
|
+
// }
|
|
510
|
+
.mapNotNull {
|
|
511
|
+
when (it) {
|
|
512
|
+
// is NotificationButton.BACKWARD -> {
|
|
513
|
+
// Log.d("CustomActionProvider IN", "CustomActionProvider IN rewind " + it.customAction.toString())
|
|
514
|
+
// createMediaSessionAction(rewindIcon ?: DEFAULT_REWIND_ICON, REWIND)
|
|
515
|
+
// }
|
|
516
|
+
// is NotificationButton.FORWARD -> {
|
|
517
|
+
// Log.d("CustomActionProvider IN", "CustomActionProvider IN forward " + it.customAction.toString())
|
|
518
|
+
// createMediaSessionAction(forwardIcon ?: DEFAULT_FORWARD_ICON, FORWARD)
|
|
519
|
+
// }
|
|
520
|
+
// is NotificationButton.STOP -> {
|
|
521
|
+
// Log.d("CustomActionProvider IN", "CustomActionProvider IN stop " + it.customAction.toString())
|
|
522
|
+
// createMediaSessionAction(stopIcon ?: DEFAULT_STOP_ICON, STOP)
|
|
523
|
+
// }
|
|
524
|
+
is NotificationButton.CUSTOM_ACTION -> {
|
|
525
|
+
createMediaSessionAction(customIcons[it.customAction] ?: DEFAULT_CUSTOM_ICON, it.customAction ?: "NO_ACTION_CODE_PROVIDED")
|
|
526
|
+
}
|
|
527
|
+
else -> {
|
|
528
|
+
null
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
mediaSessionConnector.setCustomActionProviders(*customActionProviders.toTypedArray())
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
internalNotificationManager =
|
|
537
|
+
PlayerNotificationManager.Builder(context, NOTIFICATION_ID, CHANNEL_ID)
|
|
538
|
+
.apply {
|
|
539
|
+
// setChannelNameResourceId(R.string.playback_channel_name)
|
|
540
|
+
setMediaDescriptionAdapter(descriptionAdapter)
|
|
541
|
+
setCustomActionReceiver(customActionReceiver)
|
|
542
|
+
setNotificationListener(this@NotificationManager)
|
|
543
|
+
|
|
544
|
+
internalNotificationManager.apply {
|
|
545
|
+
showPlayPauseButton = false
|
|
546
|
+
showForwardButton = false
|
|
547
|
+
showRewindButton = false
|
|
548
|
+
showNextButton = false
|
|
549
|
+
showPreviousButton = false
|
|
550
|
+
showStopButton = false
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
for (button in buttons) {
|
|
554
|
+
if (button == null) continue
|
|
555
|
+
when (button) {
|
|
556
|
+
is NotificationButton.PLAY_PAUSE -> {
|
|
557
|
+
button.playIcon?.let { setPlayActionIconResourceId(it) }
|
|
558
|
+
button.pauseIcon?.let { setPauseActionIconResourceId(it) }
|
|
559
|
+
}
|
|
560
|
+
is NotificationButton.NEXT -> button.icon?.let {
|
|
561
|
+
setNextActionIconResourceId(
|
|
562
|
+
it
|
|
563
|
+
)
|
|
564
|
+
}
|
|
565
|
+
is NotificationButton.PREVIOUS -> button.icon?.let {
|
|
566
|
+
setPreviousActionIconResourceId(
|
|
567
|
+
it
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
else -> {}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}.build().apply {
|
|
574
|
+
setColor(config.accentColor ?: Color.TRANSPARENT)
|
|
575
|
+
config.smallIcon?.let { setSmallIcon(it) }
|
|
576
|
+
for (button in buttons) {
|
|
577
|
+
if (button == null) continue
|
|
578
|
+
when (button) {
|
|
579
|
+
is NotificationButton.PLAY_PAUSE -> {
|
|
580
|
+
showPlayPauseButton = true
|
|
581
|
+
}
|
|
582
|
+
is NotificationButton.STOP -> {
|
|
583
|
+
showStopButton = true
|
|
584
|
+
}
|
|
585
|
+
is NotificationButton.FORWARD -> {
|
|
586
|
+
showForwardButton = true
|
|
587
|
+
showForwardButtonCompact = button.isCompact
|
|
588
|
+
}
|
|
589
|
+
is NotificationButton.BACKWARD -> {
|
|
590
|
+
showRewindButton = true
|
|
591
|
+
showRewindButtonCompact = button.isCompact
|
|
592
|
+
}
|
|
593
|
+
is NotificationButton.NEXT -> {
|
|
594
|
+
showNextButton = true
|
|
595
|
+
showNextButtonCompact = button.isCompact
|
|
596
|
+
}
|
|
597
|
+
is NotificationButton.PREVIOUS -> {
|
|
598
|
+
showPreviousButton = true
|
|
599
|
+
showPreviousButtonCompact = button.isCompact
|
|
600
|
+
}
|
|
601
|
+
else -> {}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// REMOVE THE COMMENTS BELOW TO USE ANDROID AUTO PLAYER NOTIFICATION
|
|
606
|
+
|
|
607
|
+
//setMediaSessionToken(mediaSession.sessionToken)
|
|
608
|
+
// setPlayer(player)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
fun hideNotification() = scope.launch {
|
|
613
|
+
internalNotificationManager?.setPlayer(null)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
override fun onNotificationPosted(
|
|
617
|
+
notificationId: Int,
|
|
618
|
+
notification: Notification,
|
|
619
|
+
ongoing: Boolean
|
|
620
|
+
) {
|
|
621
|
+
scope.launch {
|
|
622
|
+
event.updateNotificationState(
|
|
623
|
+
NotificationState.POSTED(
|
|
624
|
+
notificationId,
|
|
625
|
+
notification,
|
|
626
|
+
ongoing
|
|
627
|
+
)
|
|
628
|
+
)
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
|
|
633
|
+
scope.launch {
|
|
634
|
+
event.updateNotificationState(NotificationState.CANCELLED(notificationId))
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
internal fun destroy() = scope.launch {
|
|
639
|
+
internalNotificationManager?.setPlayer(null)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
private fun createMediaSessionAction(
|
|
643
|
+
@DrawableRes drawableRes: Int,
|
|
644
|
+
actionName: String
|
|
645
|
+
): MediaSessionConnector.CustomActionProvider {
|
|
646
|
+
return object : MediaSessionConnector.CustomActionProvider {
|
|
647
|
+
override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? {
|
|
648
|
+
return PlaybackStateCompat.CustomAction.Builder(actionName, actionName, drawableRes)
|
|
649
|
+
.build()
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
override fun onCustomAction(player: Player, action: String, extras: Bundle?) {
|
|
653
|
+
handlePlayerAction(action)
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
companion object {
|
|
659
|
+
// Due to the removal of rewind, forward, and stop buttons from the standard notification
|
|
660
|
+
// controls in Android 13, custom actions are implemented to support them
|
|
661
|
+
// https://developer.android.com/about/versions/13/behavior-changes-13#playback-controls
|
|
662
|
+
private val needsCustomActionsToAddMissingButtons = true
|
|
663
|
+
public const val REWIND = "rewind"
|
|
664
|
+
public const val FORWARD = "forward"
|
|
665
|
+
public const val STOP = "stop"
|
|
666
|
+
public const val SHUFFLE = "shuffle"
|
|
667
|
+
private const val NOTIFICATION_ID = 1
|
|
668
|
+
private const val CHANNEL_ID = "kotlin_audio_player"
|
|
669
|
+
private val DEFAULT_STOP_ICON =
|
|
670
|
+
com.google.android.exoplayer2.ui.R.drawable.exo_notification_stop
|
|
671
|
+
private val DEFAULT_REWIND_ICON =
|
|
672
|
+
com.google.android.exoplayer2.ui.R.drawable.exo_notification_rewind
|
|
673
|
+
private val DEFAULT_FORWARD_ICON =
|
|
674
|
+
com.google.android.exoplayer2.ui.R.drawable.exo_notification_fastforward
|
|
675
|
+
private val DEFAULT_CUSTOM_ICON =
|
|
676
|
+
com.google.android.exoplayer2.ui.R.drawable.exo_edit_mode_logo
|
|
677
|
+
}
|
|
678
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.kotlinaudio.players
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.doublesymmetry.kotlinaudio.players.BaseAudioPlayer
|
|
5
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.BufferConfig
|
|
6
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.CacheConfig
|
|
7
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.PlayerConfig
|
|
8
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.AAMediaSessionCallBack
|
|
9
|
+
|
|
10
|
+
class AudioPlayer(context: Context, playerConfig: PlayerConfig = PlayerConfig(), bufferConfig: BufferConfig? = null, cacheConfig: CacheConfig? = null, mediaSessionCallback: AAMediaSessionCallBack): BaseAudioPlayer(context, playerConfig, bufferConfig, cacheConfig, mediaSessionCallback)
|