diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5e4a8f29..44833801 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -23,18 +23,18 @@ android:theme="@style/AppTheme" android:usesCleartextTraffic="true" > - - - - - - - + + + + + - - - - + + ?) { + super.onResourceReady(resource, transition) + } + } + + val artist = playbackSession?.displayAuthor ?: "Unknown" + views.setTextViewText(R.id.widgetArtistText, artist) + + val title = playbackSession?.displayTitle ?: "Unknown" + views.setTextViewText(R.id.widgetMediaTitle, title) + + val options = RequestOptions().override(300, 300).placeholder(R.drawable.icon).error(R.drawable.icon) + Glide.with(context.applicationContext).asBitmap().load(imageUri).apply(options).into(awt) + + Log.i(tag, "Update App Widget | Is Playing=$isPlaying | isAppClosed=$isAppClosed") + + val playPauseResource = if (isPlaying) R.drawable.ic_media_pause_dark else R.drawable.ic_media_play_dark + views.setImageViewResource(R.id.widgetPlayPauseButton, playPauseResource) + + // Instruct the widget manager to update the widget + appWidgetManager.updateAppWidget(appWidgetId, views) +} diff --git a/android/app/src/main/java/com/audiobookshelf/app/NewAppWidget.kt b/android/app/src/main/java/com/audiobookshelf/app/NewAppWidget.kt deleted file mode 100644 index c160ca06..00000000 --- a/android/app/src/main/java/com/audiobookshelf/app/NewAppWidget.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.audiobookshelf.app - -import android.app.PendingIntent -import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProvider -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.graphics.Bitmap -import android.net.Uri -import android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_PAUSE -import android.util.Log -import android.widget.RemoteViews -import androidx.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent -import com.audiobookshelf.app.device.DeviceManager -import com.audiobookshelf.app.device.WidgetEventEmitter -import com.audiobookshelf.app.player.PlayerNotificationService -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.bumptech.glide.request.target.AppWidgetTarget -import com.bumptech.glide.request.transition.Transition - -/** - * Implementation of App Widget functionality. - */ -class NewAppWidget : AppWidgetProvider() { - val tag = "NewAppWidget" - - override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { - // There may be multiple widgets active, so update all of them - for (appWidgetId in appWidgetIds) { - updateAppWidget(context, appWidgetManager, appWidgetId, null,false) - } - } - - override fun onEnabled(context: Context) { - Log.w(tag, "onEnabled check context ${context.packageName}") - - // Enter relevant functionality for when the first widget is created - DeviceManager.widgetUpdater = (object : WidgetEventEmitter { - override fun onPlayerChanged(pns:PlayerNotificationService) { - val isPlaying = pns.currentPlayer.isPlaying - Log.i(tag, "onPlayerChanged | Is Playing? $isPlaying") - - val appWidgetManager = AppWidgetManager.getInstance(context) - val componentName = ComponentName(context, NewAppWidget::class.java) - val ids = appWidgetManager.getAppWidgetIds(componentName) - - val playbackSession = pns.getCurrentPlaybackSessionCopy() - val cover = playbackSession?.getCoverUri() - - for (widgetId in ids) { - updateAppWidget(context, appWidgetManager, widgetId, cover, isPlaying) - } - } - }) - } - - override fun onDisabled(context: Context) { - // Enter relevant functionality for when the last widget is disabled - } -} - -internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, coverUri:Uri?, isPlaying:Boolean) { - - val views = RemoteViews(context.packageName, R.layout.new_app_widget) - - val playPausePI = buildMediaButtonPendingIntent(context, ACTION_PLAY_PAUSE) - views.setOnClickPendingIntent(R.id.playPauseIcon, playPausePI) - - val wholeWidgetClickI = Intent(context, MainActivity::class.java) - wholeWidgetClickI.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK - val wholeWidgetClickPI = PendingIntent.getActivity( - context, - System.currentTimeMillis().toInt(), - wholeWidgetClickI, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - views.setOnClickPendingIntent(R.id.appWidget, wholeWidgetClickPI) - - val imageUri = coverUri ?: Uri.parse("android.resource://com.audiobookshelf.app/" + R.drawable.icon) - val awt: AppWidgetTarget = object : AppWidgetTarget(context.applicationContext, R.id.imageView, views, appWidgetId) { - override fun onResourceReady(resource: Bitmap, transition: Transition?) { - super.onResourceReady(resource, transition) - } - } - - val options = RequestOptions().override(300, 300).placeholder(R.drawable.icon).error(R.drawable.icon) - Glide.with(context.applicationContext).asBitmap().load(imageUri).apply(options).into(awt) - - val playPauseResource = if (isPlaying) R.drawable.ic_media_pause_dark else R.drawable.ic_media_play_dark - views.setImageViewResource(R.id.playPauseIcon, playPauseResource) - - // Instruct the widget manager to update the widget - appWidgetManager.updateAppWidget(appWidgetId, views) -} diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt index 222bd5f6..036856d2 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt @@ -190,6 +190,16 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi handleMediaButtonClickCount() } } + KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> { + Log.d(tag, "handleCallMediaButton: Media Fast Forward") + if (0 == mediaButtonClickCount) playerNotificationService.jumpForward() + handleMediaButtonClickCount() + } + KeyEvent.KEYCODE_MEDIA_REWIND -> { + Log.d(tag, "handleCallMediaButton: Media Rewind") + if (0 == mediaButtonClickCount) playerNotificationService.jumpBackward() + handleMediaButtonClickCount() + } } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 71f12af6..f21b93a2 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -1,6 +1,8 @@ package com.audiobookshelf.app.player import android.app.* +import android.appwidget.AppWidgetManager +import android.content.ComponentName import android.content.Context import android.content.Intent import android.graphics.Bitmap @@ -21,12 +23,15 @@ import android.support.v4.media.session.MediaControllerCompat import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import android.util.Log +import android.view.View +import android.widget.RemoteViews import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.media.MediaBrowserServiceCompat import androidx.media.utils.MediaConstants import com.audiobookshelf.app.BuildConfig +import com.audiobookshelf.app.MediaPlayerWidget import com.audiobookshelf.app.R import com.audiobookshelf.app.data.* import com.audiobookshelf.app.data.DeviceInfo @@ -170,12 +175,16 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } Log.d(tag, "onDestroy") + isStarted = false + isClosed = true + DeviceManager.widgetUpdater?.onPlayerChanged(this) + playerNotificationManager.setPlayer(null) mPlayer.release() castPlayer?.release() mediaSession.release() mediaProgressSyncer.reset() - isStarted = false + super.onDestroy() } @@ -184,6 +193,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { override fun onTaskRemoved(rootIntent: Intent?) { super.onTaskRemoved(rootIntent) Log.d(tag, "onTaskRemoved") + stopSelf() } @@ -258,7 +268,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { playerNotificationManager.setPriority(NotificationCompat.PRIORITY_MAX) playerNotificationManager.setUseFastForwardActionInCompactView(true) playerNotificationManager.setUseRewindActionInCompactView(true) - playerNotificationManager.setSmallIcon(R.drawable.exo_icon_localaudio) + playerNotificationManager.setSmallIcon(R.drawable.icon_monochrome) // Unknown action playerNotificationManager.setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE) @@ -409,9 +419,12 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { DeviceManager.setLastPlaybackSession(playbackSession) // Save playback session to use when app is closed Log.d(tag, "Set CurrentPlaybackSession MediaPlayer ${currentPlaybackSession?.mediaPlayer}") - + // Notify client clientEventEmitter?.onPlaybackSession(playbackSession) + // Update widget + DeviceManager.widgetUpdater?.onPlayerChanged(this) + if (mediaItems.isEmpty()) { Log.e(tag, "Invalid playback session no media items to play") currentPlaybackSession = null diff --git a/android/app/src/main/res/drawable-nodpi/example_appwidget_preview.png b/android/app/src/main/res/drawable-nodpi/example_appwidget_preview.png deleted file mode 100644 index 894b069a..00000000 Binary files a/android/app/src/main/res/drawable-nodpi/example_appwidget_preview.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-nodpi/media_player_widget_preview.png b/android/app/src/main/res/drawable-nodpi/media_player_widget_preview.png new file mode 100644 index 00000000..27a07efe Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/media_player_widget_preview.png differ diff --git a/android/app/src/main/res/drawable/icon_monochrome.xml b/android/app/src/main/res/drawable/icon_monochrome.xml new file mode 100644 index 00000000..594c52c7 --- /dev/null +++ b/android/app/src/main/res/drawable/icon_monochrome.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/layout/media_player_widget.xml b/android/app/src/main/res/layout/media_player_widget.xml new file mode 100644 index 00000000..a71a7d33 --- /dev/null +++ b/android/app/src/main/res/layout/media_player_widget.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/new_app_widget.xml b/android/app/src/main/res/layout/new_app_widget.xml deleted file mode 100644 index 99ac1b46..00000000 --- a/android/app/src/main/res/layout/new_app_widget.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - diff --git a/android/app/src/main/res/values-night-v31/themes.xml b/android/app/src/main/res/values-night-v31/themes.xml new file mode 100644 index 00000000..db9d77f0 --- /dev/null +++ b/android/app/src/main/res/values-night-v31/themes.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/android/app/src/main/res/values-v31/styles.xml b/android/app/src/main/res/values-v31/styles.xml new file mode 100644 index 00000000..3a0135c0 --- /dev/null +++ b/android/app/src/main/res/values-v31/styles.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/android/app/src/main/res/values-v31/themes.xml b/android/app/src/main/res/values-v31/themes.xml new file mode 100644 index 00000000..8ffe2e9f --- /dev/null +++ b/android/app/src/main/res/values-v31/themes.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/android/app/src/main/res/values/attrs.xml b/android/app/src/main/res/values/attrs.xml index 7781ac86..3f37ec30 100644 --- a/android/app/src/main/res/values/attrs.xml +++ b/android/app/src/main/res/values/attrs.xml @@ -1,7 +1,9 @@ - - - - - - \ No newline at end of file + + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 713e8445..4234d998 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,33 +1,42 @@ - - + + - + - - + - + + + + + diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml index 254f4a55..fc7585c3 100644 --- a/android/app/src/main/res/values/themes.xml +++ b/android/app/src/main/res/values/themes.xml @@ -1,17 +1,17 @@ - + 0dp + - + diff --git a/android/app/src/main/res/xml/media_player_widget_info.xml b/android/app/src/main/res/xml/media_player_widget_info.xml new file mode 100644 index 00000000..45dab3b3 --- /dev/null +++ b/android/app/src/main/res/xml/media_player_widget_info.xml @@ -0,0 +1,14 @@ + + diff --git a/android/app/src/main/res/xml/new_app_widget_info.xml b/android/app/src/main/res/xml/new_app_widget_info.xml deleted file mode 100644 index ffa76ee7..00000000 --- a/android/app/src/main/res/xml/new_app_widget_info.xml +++ /dev/null @@ -1,12 +0,0 @@ - -