Add ability to exit notification

Add an exit button to the notification so that one can exit it.
This commit is contained in:
OxygenCobalt 2020-11-01 15:37:01 -07:00
parent 5da3fa866b
commit 660f4c0eb7
19 changed files with 72 additions and 61 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

@ -1,7 +1,10 @@
package org.oxycblt.auxio package org.oxycblt.auxio
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity

View file

@ -33,6 +33,8 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
findNavController().navigate( findNavController().navigate(
LoadingFragmentDirections.actionToMain() LoadingFragmentDirections.actionToMain()
) )
return null
} }
val binding = FragmentLoadingBinding.inflate(inflater) val binding = FragmentLoadingBinding.inflate(inflater)

View file

@ -8,6 +8,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.media.app.NotificationCompat.MediaStyle import androidx.media.app.NotificationCompat.MediaStyle
import org.oxycblt.auxio.MainActivity import org.oxycblt.auxio.MainActivity
@ -26,7 +27,7 @@ object NotificationUtils {
const val ACTION_SKIP_PREV = "ACTION_AUXIO_SKIP_PREV" const val ACTION_SKIP_PREV = "ACTION_AUXIO_SKIP_PREV"
const val ACTION_PLAY_PAUSE = "ACTION_AUXIO_PLAY_PAUSE" const val ACTION_PLAY_PAUSE = "ACTION_AUXIO_PLAY_PAUSE"
const val ACTION_SKIP_NEXT = "ACTION_AUXIO_SKIP_NEXT" const val ACTION_SKIP_NEXT = "ACTION_AUXIO_SKIP_NEXT"
const val ACTION_SHUFFLE = "ACTION_AUXIO_SHUFFLE" const val ACTION_EXIT = "ACTION_AUXIO_EXIT"
} }
fun NotificationManager.createMediaNotification( fun NotificationManager.createMediaNotification(
@ -51,7 +52,9 @@ fun NotificationManager.createMediaNotification(
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
) )
// TODO: It would be cool if the notification intent took you to the now playing screen. // TODO: Things that probably aren't possible but would be nice
// - Swipe to close instead of a button to press
// - Playing intent takes you to now playing screen instead of elsewhere
return NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID) return NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID)
.setSmallIcon(R.drawable.ic_song) .setSmallIcon(R.drawable.ic_song)
.setStyle( .setStyle(
@ -67,7 +70,7 @@ fun NotificationManager.createMediaNotification(
.addAction(newAction(NotificationUtils.ACTION_SKIP_PREV, context)) .addAction(newAction(NotificationUtils.ACTION_SKIP_PREV, context))
.addAction(newAction(NotificationUtils.ACTION_PLAY_PAUSE, context)) .addAction(newAction(NotificationUtils.ACTION_PLAY_PAUSE, context))
.addAction(newAction(NotificationUtils.ACTION_SKIP_NEXT, context)) .addAction(newAction(NotificationUtils.ACTION_SKIP_NEXT, context))
.addAction(newAction(NotificationUtils.ACTION_SHUFFLE, context)) .addAction(newAction(NotificationUtils.ACTION_EXIT, context))
.setSubText(context.getString(R.string.title_playback)) .setSubText(context.getString(R.string.title_playback))
.setContentIntent(mainIntent) .setContentIntent(mainIntent)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
@ -86,19 +89,16 @@ fun NotificationCompat.Builder.setMetadata(song: Song, context: Context, onDone:
} }
} }
@SuppressLint("RestrictedApi")
fun NotificationCompat.Builder.updateLoop(context: Context) {
mActions[0] = newAction(NotificationUtils.ACTION_LOOP, context)
}
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
fun NotificationCompat.Builder.updatePlaying(context: Context) { fun NotificationCompat.Builder.updatePlaying(context: Context) {
mActions[2] = newAction(NotificationUtils.ACTION_PLAY_PAUSE, context) mActions[2] = newAction(NotificationUtils.ACTION_PLAY_PAUSE, context)
setOngoing(PlaybackStateManager.getInstance().isPlaying)
} }
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
fun NotificationCompat.Builder.updateShuffle(context: Context) { fun NotificationCompat.Builder.updateLoop(context: Context) {
mActions[4] = newAction(NotificationUtils.ACTION_SHUFFLE, context) mActions[0] = newAction(NotificationUtils.ACTION_LOOP, context)
} }
private fun newAction(action: String, context: Context): NotificationCompat.Action { private fun newAction(action: String, context: Context): NotificationCompat.Action {
@ -113,9 +113,7 @@ private fun newAction(action: String, context: Context): NotificationCompat.Acti
} }
} }
NotificationUtils.ACTION_SKIP_PREV -> { NotificationUtils.ACTION_SKIP_PREV -> R.drawable.ic_skip_prev
R.drawable.ic_skip_prev
}
NotificationUtils.ACTION_PLAY_PAUSE -> { NotificationUtils.ACTION_PLAY_PAUSE -> {
if (playbackManager.isPlaying) { if (playbackManager.isPlaying) {
@ -125,18 +123,9 @@ private fun newAction(action: String, context: Context): NotificationCompat.Acti
} }
} }
NotificationUtils.ACTION_SKIP_NEXT -> { NotificationUtils.ACTION_SKIP_NEXT -> R.drawable.ic_skip_next
R.drawable.ic_skip_next
}
NotificationUtils.ACTION_SHUFFLE -> {
if (playbackManager.isShuffling) {
R.drawable.ic_shuffle
} else {
R.drawable.ic_shuffle_disabled
}
}
NotificationUtils.ACTION_EXIT -> R.drawable.ic_exit
else -> R.drawable.ic_play else -> R.drawable.ic_play
} }

View file

@ -9,6 +9,7 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.ServiceInfo import android.content.pm.ServiceInfo
import android.media.AudioManager import android.media.AudioManager
import android.os.Binder
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.Parcelable import android.os.Parcelable
@ -56,6 +57,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
private var changeIsFromAudioFocus = true private var changeIsFromAudioFocus = true
private var isForeground = false private var isForeground = false
private var isDetachedFromUI = false
private val serviceJob = Job() private val serviceJob = Job()
private val serviceScope = CoroutineScope( private val serviceScope = CoroutineScope(
@ -70,7 +72,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
return START_NOT_STICKY return START_NOT_STICKY
} }
override fun onBind(intent: Intent): IBinder? = null override fun onBind(intent: Intent): IBinder? = LocalBinder()
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -113,7 +115,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
addAction(NotificationUtils.ACTION_SKIP_PREV) addAction(NotificationUtils.ACTION_SKIP_PREV)
addAction(NotificationUtils.ACTION_PLAY_PAUSE) addAction(NotificationUtils.ACTION_PLAY_PAUSE)
addAction(NotificationUtils.ACTION_SKIP_NEXT) addAction(NotificationUtils.ACTION_SKIP_NEXT)
addAction(NotificationUtils.ACTION_SHUFFLE) addAction(NotificationUtils.ACTION_EXIT)
addAction(BluetoothDevice.ACTION_ACL_CONNECTED) addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED) addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
@ -229,19 +231,11 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
startPollingPosition() startPollingPosition()
} else { } else {
player.pause() player.pause()
notification.updatePlaying(this) notification.updatePlaying(this)
startForegroundOrNotify() startForegroundOrNotify()
} }
} }
override fun onShuffleUpdate(isShuffling: Boolean) {
changeIsFromAudioFocus = false
notification.updateShuffle(this)
startForegroundOrNotify()
}
override fun onLoopUpdate(mode: LoopMode) { override fun onLoopUpdate(mode: LoopMode) {
changeIsFromAudioFocus = false changeIsFromAudioFocus = false
@ -390,8 +384,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
NotificationUtils.ACTION_PLAY_PAUSE -> NotificationUtils.ACTION_PLAY_PAUSE ->
playbackManager.setPlayingStatus(!playbackManager.isPlaying) playbackManager.setPlayingStatus(!playbackManager.isPlaying)
NotificationUtils.ACTION_SKIP_NEXT -> playbackManager.next() NotificationUtils.ACTION_SKIP_NEXT -> playbackManager.next()
NotificationUtils.ACTION_SHUFFLE -> NotificationUtils.ACTION_EXIT -> stop()
playbackManager.setShuffleStatus(!playbackManager.isShuffling)
BluetoothDevice.ACTION_ACL_CONNECTED -> resume() BluetoothDevice.ACTION_ACL_CONNECTED -> resume()
BluetoothDevice.ACTION_ACL_DISCONNECTED -> pause() BluetoothDevice.ACTION_ACL_DISCONNECTED -> pause()
@ -430,6 +423,15 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
playbackManager.setPlayingStatus(false) playbackManager.setPlayingStatus(false)
} }
} }
private fun stop() {
playbackManager.setPlayingStatus(false)
stopForegroundAndNotification()
}
}
inner class LocalBinder : Binder() {
fun getService() = this@PlaybackService
} }
companion object { companion object {

View file

@ -4,24 +4,29 @@
android:height="108dp" android:height="108dp"
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<path <group android:scaleX="0.95"
android:pathData="M 54.000004,28.557237 V 58.38181 c -1.667916,-0.96117 -3.590261,-1.554837 -5.65395,-1.554837 -6.247608,0 -11.307896,5.060283 -11.307896,11.307898 0,6.24761 5.060288,11.307892 11.307896,11.307892 6.24761,0 11.307898,-5.06028 11.307898,-11.307891 V 39.865131 H 70.961841 V 28.557237 Z" android:scaleY="0.95"
android:strokeWidth="0.890156" android:translateX="2.7"
android:strokeColor="#ffffff"> android:translateY="2.7">
<aapt:attr name="android:fillColor"> <path
<gradient android:pathData="M 54.000004,28.557237 V 58.38181 c -1.667916,-0.96117 -3.590261,-1.554837 -5.65395,-1.554837 -6.247608,0 -11.307896,5.060283 -11.307896,11.307898 0,6.24761 5.060288,11.307892 11.307896,11.307892 6.24761,0 11.307898,-5.06028 11.307898,-11.307891 V 39.865131 H 70.961841 V 28.557237 Z"
android:startX="60" android:strokeWidth="0.890156"
android:startY="61.5" android:strokeColor="#ffffff">
android:endX="64.75" <aapt:attr name="android:fillColor">
android:endY="28.5" <gradient
android:type="linear"> android:startX="60"
<item android:startY="61.5"
android:color="#2196f3" android:endX="64.75"
android:offset="0.0" /> android:endY="28.5"
<item android:type="linear">
android:color="#90caf9" <item
android:offset="1.0" /> android:color="#2196f3"
</gradient> android:offset="0.0" />
</aapt:attr> <item
</path> android:color="#90caf9"
</vector> android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
</group>
</vector>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<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="@android:color/white"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1,021 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB