[Notification] Fixed and improved playing notification
This commit is contained in:
parent
ba9c928588
commit
1df50491fc
4 changed files with 482 additions and 443 deletions
|
@ -25,6 +25,7 @@ import static code.name.monkey.retromusic.ConstantsKt.CROSS_FADE_DURATION;
|
||||||
import static code.name.monkey.retromusic.ConstantsKt.TOGGLE_HEADSET;
|
import static code.name.monkey.retromusic.ConstantsKt.TOGGLE_HEADSET;
|
||||||
import static code.name.monkey.retromusic.service.AudioFader.startFadeAnimator;
|
import static code.name.monkey.retromusic.service.AudioFader.startFadeAnimator;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
@ -34,6 +35,7 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.ServiceInfo;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
@ -106,6 +108,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
import code.name.monkey.retromusic.util.RetroUtil;
|
||||||
import code.name.monkey.retromusic.volume.AudioVolumeObserver;
|
import code.name.monkey.retromusic.volume.AudioVolumeObserver;
|
||||||
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener;
|
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener;
|
||||||
|
import kotlin.Unit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karim Abou Zeid (kabouzeid), Andrew Neal
|
* @author Karim Abou Zeid (kabouzeid), Andrew Neal
|
||||||
|
@ -280,7 +283,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
new BroadcastReceiver() {
|
new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
updateNotification();
|
playingNotification.updateFavorite(getCurrentSong(), MusicService.this::startForegroundOrNotify);
|
||||||
|
startForegroundOrNotify();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final BroadcastReceiver lockScreenReceiver =
|
private final BroadcastReceiver lockScreenReceiver =
|
||||||
|
@ -363,6 +367,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
private ThrottledSeekHandler throttledSeekHandler;
|
private ThrottledSeekHandler throttledSeekHandler;
|
||||||
private Handler uiThreadHandler;
|
private Handler uiThreadHandler;
|
||||||
private PowerManager.WakeLock wakeLock;
|
private PowerManager.WakeLock wakeLock;
|
||||||
|
private NotificationManager notificationManager;
|
||||||
|
private boolean isForeground = false;
|
||||||
|
|
||||||
private static Bitmap copy(Bitmap bitmap) {
|
private static Bitmap copy(Bitmap bitmap) {
|
||||||
Bitmap.Config config = bitmap.getConfig();
|
Bitmap.Config config = bitmap.getConfig();
|
||||||
|
@ -424,6 +430,10 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
registerReceiver(updateFavoriteReceiver, new IntentFilter(FAVORITE_STATE_CHANGED));
|
registerReceiver(updateFavoriteReceiver, new IntentFilter(FAVORITE_STATE_CHANGED));
|
||||||
registerReceiver(lockScreenReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
registerReceiver(lockScreenReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||||
|
|
||||||
|
setSessionToken(mediaSession.getSessionToken());
|
||||||
|
if (VersionUtils.INSTANCE.hasMarshmallow()) {
|
||||||
|
notificationManager = getSystemService(NotificationManager.class);
|
||||||
|
}
|
||||||
initNotification();
|
initNotification();
|
||||||
|
|
||||||
mediaStoreObserver = new MediaStoreObserver(this, playerHandler);
|
mediaStoreObserver = new MediaStoreObserver(this, playerHandler);
|
||||||
|
@ -474,7 +484,6 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
|
|
||||||
mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers);
|
mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers);
|
||||||
mMusicProvider.setMusicService(this);
|
mMusicProvider.setMusicService(this);
|
||||||
setSessionToken(mediaSession.getSessionToken());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -772,11 +781,10 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
public void initNotification() {
|
public void initNotification() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
||||||
&& !PreferenceUtil.INSTANCE.isClassicNotification()) {
|
&& !PreferenceUtil.INSTANCE.isClassicNotification()) {
|
||||||
playingNotification = new PlayingNotificationImpl();
|
playingNotification = PlayingNotificationImpl.Companion.from(this, notificationManager, mediaSession);
|
||||||
} else {
|
} else {
|
||||||
playingNotification = new PlayingNotificationOreo();
|
playingNotification = PlayingNotificationOreo.Companion.from(this, notificationManager);
|
||||||
}
|
}
|
||||||
playingNotification.init(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLastTrack() {
|
public boolean isLastTrack() {
|
||||||
|
@ -844,7 +852,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
// Request from an untrusted package: return an empty browser root
|
// Request from an untrusted package: return an empty browser root
|
||||||
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
|
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
|
||||||
} else {
|
} else {
|
||||||
/** By default return the browsable root. Treat the EXTRA_RECENT flag as a special case
|
/**
|
||||||
|
* By default return the browsable root. Treat the EXTRA_RECENT flag as a special case
|
||||||
* and return the recent root instead.
|
* and return the recent root instead.
|
||||||
*/
|
*/
|
||||||
boolean isRecentRequest = false;
|
boolean isRecentRequest = false;
|
||||||
|
@ -1049,6 +1058,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause() {
|
public void pause() {
|
||||||
|
Log.i(TAG, "Paused");
|
||||||
pausedByTransientLossOfFocus = false;
|
pausedByTransientLossOfFocus = false;
|
||||||
if (playback != null && playback.isPlaying()) {
|
if (playback != null && playback.isPlaying()) {
|
||||||
startFadeAnimator(playback, false, () -> {
|
startFadeAnimator(playback, false, () -> {
|
||||||
|
@ -1170,7 +1180,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
|
|
||||||
public void quit() {
|
public void quit() {
|
||||||
pause();
|
pause();
|
||||||
playingNotification.stop();
|
stopForeground(true);
|
||||||
|
notificationManager.cancel(PlayingNotification.NOTIFICATION_ID);
|
||||||
|
|
||||||
closeAudioEffectSession();
|
closeAudioEffectSession();
|
||||||
getAudioManager().abandonAudioFocus(audioFocusListener);
|
getAudioManager().abandonAudioFocus(audioFocusListener);
|
||||||
|
@ -1333,7 +1344,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
|
|
||||||
public void updateNotification() {
|
public void updateNotification() {
|
||||||
if (playingNotification != null && getCurrentSong().getId() != -1) {
|
if (playingNotification != null && getCurrentSong().getId() != -1) {
|
||||||
playingNotification.update();
|
stopForegroundAndNotification();
|
||||||
|
initNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,17 +1419,19 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
private void handleChangeInternal(@NonNull final String what) {
|
private void handleChangeInternal(@NonNull final String what) {
|
||||||
switch (what) {
|
switch (what) {
|
||||||
case PLAY_STATE_CHANGED:
|
case PLAY_STATE_CHANGED:
|
||||||
updateNotification();
|
|
||||||
updateMediaSessionPlaybackState();
|
updateMediaSessionPlaybackState();
|
||||||
final boolean isPlaying = isPlaying();
|
final boolean isPlaying = isPlaying();
|
||||||
if (!isPlaying && getSongProgressMillis() > 0) {
|
if (!isPlaying && getSongProgressMillis() > 0) {
|
||||||
savePositionInTrack();
|
savePositionInTrack();
|
||||||
}
|
}
|
||||||
songPlayCountHelper.notifyPlayStateChanged(isPlaying);
|
songPlayCountHelper.notifyPlayStateChanged(isPlaying);
|
||||||
|
playingNotification.setPlaying(isPlaying);
|
||||||
|
startForegroundOrNotify();
|
||||||
break;
|
break;
|
||||||
case FAVORITE_STATE_CHANGED:
|
case FAVORITE_STATE_CHANGED:
|
||||||
|
playingNotification.updateFavorite(getCurrentSong(), this::startForegroundOrNotify);
|
||||||
case META_CHANGED:
|
case META_CHANGED:
|
||||||
updateNotification();
|
playingNotification.updateMetadata(getCurrentSong(), this::startForegroundOrNotify);
|
||||||
updateMediaSessionMetaData();
|
updateMediaSessionMetaData();
|
||||||
updateMediaSessionPlaybackState();
|
updateMediaSessionPlaybackState();
|
||||||
savePosition();
|
savePosition();
|
||||||
|
@ -1435,12 +1449,41 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
if (playingQueue.size() > 0) {
|
if (playingQueue.size() > 0) {
|
||||||
prepareNext();
|
prepareNext();
|
||||||
} else {
|
} else {
|
||||||
playingNotification.stop();
|
stopForegroundAndNotification();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Unit startForegroundOrNotify() {
|
||||||
|
if (!isForeground) {
|
||||||
|
// Specify that this is a media service, if supported.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
startForeground(
|
||||||
|
PlayingNotification.NOTIFICATION_ID, playingNotification.build(),
|
||||||
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
startForeground(PlayingNotification.NOTIFICATION_ID, playingNotification.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
isForeground = true;
|
||||||
|
} else {
|
||||||
|
// If we are already in foreground just update the notification
|
||||||
|
notificationManager.notify(
|
||||||
|
PlayingNotification.NOTIFICATION_ID, playingNotification.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopForegroundAndNotification() {
|
||||||
|
stopForeground(true);
|
||||||
|
notificationManager.cancel(PlayingNotification.NOTIFICATION_ID);
|
||||||
|
|
||||||
|
isForeground = false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean openCurrent() {
|
private boolean openCurrent() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -15,95 +15,51 @@
|
||||||
package code.name.monkey.retromusic.service.notification
|
package code.name.monkey.retromusic.service.notification
|
||||||
|
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context.NOTIFICATION_SERVICE
|
import android.content.Context
|
||||||
import android.content.pm.ServiceInfo
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.service.MusicService
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
|
||||||
|
|
||||||
abstract class PlayingNotification {
|
abstract class PlayingNotification(context: Context) :
|
||||||
protected lateinit var service: MusicService
|
NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) {
|
||||||
protected var stopped: Boolean = false
|
|
||||||
private var notifyMode = NOTIFY_MODE_BACKGROUND
|
|
||||||
private var notificationManager: NotificationManager? = null
|
|
||||||
|
|
||||||
|
abstract fun updateMetadata(song: Song, onUpdate: () -> Unit)
|
||||||
|
|
||||||
@Synchronized
|
abstract fun setPlaying(isPlaying: Boolean)
|
||||||
fun init(service: MusicService) {
|
|
||||||
this.service = service
|
|
||||||
notificationManager = service.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
createNotificationChannel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun update()
|
abstract fun updateFavorite(song: Song, onUpdate: () -> Unit)
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun stop() {
|
|
||||||
stopped = true
|
|
||||||
service.stopForeground(true)
|
|
||||||
notificationManager!!.cancel(NOTIFICATION_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateNotifyModeAndPostNotification(notification: Notification) {
|
|
||||||
val newNotifyMode: Int = if (service.isPlaying) {
|
|
||||||
NOTIFY_MODE_FOREGROUND
|
|
||||||
} else {
|
|
||||||
NOTIFY_MODE_BACKGROUND
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notifyMode != newNotifyMode && newNotifyMode == NOTIFY_MODE_BACKGROUND) {
|
|
||||||
service.stopForeground(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newNotifyMode == NOTIFY_MODE_FOREGROUND) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
service.startForeground(
|
|
||||||
NOTIFICATION_ID,
|
|
||||||
notification,
|
|
||||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
service.startForeground(NOTIFICATION_ID,notification)
|
|
||||||
}
|
|
||||||
} else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) {
|
|
||||||
notificationManager!!.notify(NOTIFICATION_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyMode = newNotifyMode
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(26)
|
|
||||||
private fun createNotificationChannel() {
|
|
||||||
var notificationChannel: NotificationChannel? = notificationManager!!
|
|
||||||
.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
|
|
||||||
if (notificationChannel == null) {
|
|
||||||
notificationChannel = NotificationChannel(
|
|
||||||
NOTIFICATION_CHANNEL_ID,
|
|
||||||
service.getString(R.string.playing_notification_name),
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
)
|
|
||||||
notificationChannel.description =
|
|
||||||
service.getString(R.string.playing_notification_description)
|
|
||||||
notificationChannel.enableLights(false)
|
|
||||||
notificationChannel.enableVibration(false)
|
|
||||||
notificationChannel.setShowBadge(false)
|
|
||||||
|
|
||||||
notificationManager!!.createNotificationChannel(notificationChannel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NOTIFICATION_CONTROLS_SIZE_MULTIPLIER = 1.0f
|
const val NOTIFICATION_CONTROLS_SIZE_MULTIPLIER = 1.0f
|
||||||
internal const val NOTIFICATION_CHANNEL_ID = "playing_notification"
|
internal const val NOTIFICATION_CHANNEL_ID = "playing_notification"
|
||||||
private const val NOTIFICATION_ID = 1
|
const val NOTIFICATION_ID = 1
|
||||||
private const val NOTIFY_MODE_FOREGROUND = 1
|
|
||||||
private const val NOTIFY_MODE_BACKGROUND = 0
|
|
||||||
|
@RequiresApi(26)
|
||||||
|
fun createNotificationChannel(
|
||||||
|
context: Context,
|
||||||
|
notificationManager: NotificationManager
|
||||||
|
) {
|
||||||
|
var notificationChannel: NotificationChannel? = notificationManager
|
||||||
|
.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
|
||||||
|
if (notificationChannel == null) {
|
||||||
|
notificationChannel = NotificationChannel(
|
||||||
|
NOTIFICATION_CHANNEL_ID,
|
||||||
|
context.getString(R.string.playing_notification_name),
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
)
|
||||||
|
notificationChannel.description =
|
||||||
|
context.getString(R.string.playing_notification_description)
|
||||||
|
notificationChannel.enableLights(false)
|
||||||
|
notificationChannel.enableVibration(false)
|
||||||
|
notificationChannel.setShowBadge(false)
|
||||||
|
|
||||||
|
notificationManager.createNotificationChannel(notificationChannel)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,14 +14,16 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.service.notification
|
package code.name.monkey.retromusic.service.notification
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.media.app.NotificationCompat.MediaStyle
|
import androidx.media.app.NotificationCompat.MediaStyle
|
||||||
|
@ -33,45 +35,32 @@ import code.name.monkey.retromusic.db.toSongEntity
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.service.MusicService
|
import code.name.monkey.retromusic.service.MusicService
|
||||||
import code.name.monkey.retromusic.service.MusicService.*
|
import code.name.monkey.retromusic.service.MusicService.*
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.target.SimpleTarget
|
|
||||||
import com.bumptech.glide.request.target.Target
|
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
@SuppressLint("RestrictedApi")
|
||||||
private var target: Target<BitmapPaletteWrapper>? = null
|
class PlayingNotificationImpl(
|
||||||
|
val context: Context,
|
||||||
|
mediaSessionToken: MediaSessionCompat.Token
|
||||||
|
) : PlayingNotification(context) {
|
||||||
|
|
||||||
@Synchronized
|
init {
|
||||||
override fun update() {
|
val action = Intent(context, MainActivity::class.java)
|
||||||
stopped = false
|
|
||||||
GlobalScope.launch {
|
|
||||||
val song = service.currentSong
|
|
||||||
val playlist: PlaylistEntity = MusicUtil.repository.favoritePlaylist()
|
|
||||||
val isPlaying = service.isPlaying
|
|
||||||
val isFavorite = if (playlist != null) {
|
|
||||||
val songEntity = song.toSongEntity(playlist.playListId)
|
|
||||||
MusicUtil.repository.isFavoriteSong(songEntity).isNotEmpty()
|
|
||||||
} else false
|
|
||||||
|
|
||||||
val playButtonResId =
|
|
||||||
if (isPlaying) R.drawable.ic_pause_white_48dp else R.drawable.ic_play_arrow_white_48dp
|
|
||||||
val favoriteResId =
|
|
||||||
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
|
||||||
|
|
||||||
val action = Intent(service, MainActivity::class.java)
|
|
||||||
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
val clickIntent =
|
val clickIntent =
|
||||||
PendingIntent.getActivity(
|
PendingIntent.getActivity(
|
||||||
service,
|
context,
|
||||||
0,
|
0,
|
||||||
action,
|
action,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
|
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
|
||||||
|
@ -79,28 +68,72 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
else 0
|
else 0
|
||||||
)
|
)
|
||||||
|
|
||||||
val serviceName = ComponentName(service, MusicService::class.java)
|
val serviceName = ComponentName(context, MusicService::class.java)
|
||||||
val intent = Intent(ACTION_QUIT)
|
val intent = Intent(ACTION_QUIT)
|
||||||
intent.component = serviceName
|
intent.component = serviceName
|
||||||
val deleteIntent = PendingIntent.getService(
|
val deleteIntent = PendingIntent.getService(
|
||||||
service,
|
context,
|
||||||
0,
|
0,
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or (if (VersionUtils.hasMarshmallow())
|
PendingIntent.FLAG_UPDATE_CURRENT or (if (VersionUtils.hasMarshmallow())
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
else 0)
|
else 0)
|
||||||
)
|
)
|
||||||
val bigNotificationImageSize = service.resources
|
val toggleFavorite = buildFavoriteAction(false)
|
||||||
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
val playPauseAction = buildPlayAction(true)
|
||||||
service.runOnUiThread {
|
val previousAction = NotificationCompat.Action(
|
||||||
if (target != null) {
|
R.drawable.ic_skip_previous_round_white_32dp,
|
||||||
Glide.with(service).clear(target)
|
context.getString(R.string.action_previous),
|
||||||
|
retrievePlaybackAction(ACTION_REWIND)
|
||||||
|
)
|
||||||
|
val nextAction = NotificationCompat.Action(
|
||||||
|
R.drawable.ic_skip_next_round_white_32dp,
|
||||||
|
context.getString(R.string.action_next),
|
||||||
|
retrievePlaybackAction(ACTION_SKIP)
|
||||||
|
)
|
||||||
|
val dismissAction = NotificationCompat.Action(
|
||||||
|
R.drawable.ic_close,
|
||||||
|
context.getString(R.string.customactivityoncrash_error_activity_error_details_close),
|
||||||
|
retrievePlaybackAction(ACTION_QUIT)
|
||||||
|
)
|
||||||
|
setSmallIcon(R.drawable.ic_notification)
|
||||||
|
setContentIntent(clickIntent)
|
||||||
|
setDeleteIntent(deleteIntent)
|
||||||
|
setShowWhen(false)
|
||||||
|
addAction(toggleFavorite)
|
||||||
|
addAction(previousAction)
|
||||||
|
addAction(playPauseAction)
|
||||||
|
addAction(nextAction)
|
||||||
|
addAction(dismissAction)
|
||||||
|
|
||||||
|
setStyle(
|
||||||
|
MediaStyle()
|
||||||
|
.setMediaSession(mediaSessionToken)
|
||||||
|
.setShowActionsInCompactView(1, 2, 3)
|
||||||
|
)
|
||||||
|
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
if (Build.VERSION.SDK_INT <=
|
||||||
|
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
|
||||||
|
) {
|
||||||
|
this.color = color
|
||||||
}
|
}
|
||||||
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
|
}
|
||||||
|
|
||||||
|
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
|
||||||
|
setContentTitle(song.title)
|
||||||
|
setContentText(
|
||||||
|
HtmlCompat.fromHtml(
|
||||||
|
"<b>" + song.albumName + "</b>",
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val bigNotificationImageSize = context.resources
|
||||||
|
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
||||||
|
GlideApp.with(context).asBitmapPalette().songCoverOptions(song)
|
||||||
.load(RetroGlideExtension.getSongModel(song))
|
.load(RetroGlideExtension.getSongModel(song))
|
||||||
//.checkIgnoreMediaStore()
|
//.checkIgnoreMediaStore()
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(object : SimpleTarget<BitmapPaletteWrapper>(
|
.into(object : CustomTarget<BitmapPaletteWrapper>(
|
||||||
bigNotificationImageSize,
|
bigNotificationImageSize,
|
||||||
bigNotificationImageSize
|
bigNotificationImageSize
|
||||||
) {
|
) {
|
||||||
|
@ -108,105 +141,90 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
resource: BitmapPaletteWrapper,
|
resource: BitmapPaletteWrapper,
|
||||||
transition: Transition<in BitmapPaletteWrapper>?
|
transition: Transition<in BitmapPaletteWrapper>?
|
||||||
) {
|
) {
|
||||||
update(
|
setLargeIcon(
|
||||||
resource.bitmap,
|
resource.bitmap
|
||||||
RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
|
|
||||||
)
|
)
|
||||||
|
if (Build.VERSION.SDK_INT <=
|
||||||
|
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
|
||||||
|
) {
|
||||||
|
color = RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
|
||||||
|
}
|
||||||
|
onUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
super.onLoadFailed(errorDrawable)
|
super.onLoadFailed(errorDrawable)
|
||||||
update(null, Color.TRANSPARENT)
|
setLargeIcon(null)
|
||||||
|
onUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(bitmap: Bitmap?, color: Int) {
|
override fun onLoadCleared(placeholder: Drawable?) {
|
||||||
var bitmapFinal = bitmap
|
setLargeIcon(null)
|
||||||
if (bitmapFinal == null) {
|
onUpdate()
|
||||||
bitmapFinal = BitmapFactory.decodeResource(
|
|
||||||
service.resources,
|
|
||||||
R.drawable.default_audio_art
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val toggleFavorite = NotificationCompat.Action(
|
|
||||||
favoriteResId,
|
|
||||||
service.getString(R.string.action_toggle_favorite),
|
|
||||||
retrievePlaybackAction(TOGGLE_FAVORITE)
|
|
||||||
)
|
|
||||||
val playPauseAction = NotificationCompat.Action(
|
|
||||||
playButtonResId,
|
|
||||||
service.getString(R.string.action_play_pause),
|
|
||||||
retrievePlaybackAction(ACTION_TOGGLE_PAUSE)
|
|
||||||
)
|
|
||||||
val previousAction = NotificationCompat.Action(
|
|
||||||
R.drawable.ic_skip_previous_round_white_32dp,
|
|
||||||
service.getString(R.string.action_previous),
|
|
||||||
retrievePlaybackAction(ACTION_REWIND)
|
|
||||||
)
|
|
||||||
val nextAction = NotificationCompat.Action(
|
|
||||||
R.drawable.ic_skip_next_round_white_32dp,
|
|
||||||
service.getString(R.string.action_next),
|
|
||||||
retrievePlaybackAction(ACTION_SKIP)
|
|
||||||
)
|
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(
|
|
||||||
service,
|
|
||||||
NOTIFICATION_CHANNEL_ID
|
|
||||||
)
|
|
||||||
.setSmallIcon(R.drawable.ic_notification)
|
|
||||||
.setLargeIcon(bitmapFinal)
|
|
||||||
.setContentIntent(clickIntent)
|
|
||||||
.setDeleteIntent(deleteIntent)
|
|
||||||
.setContentTitle(
|
|
||||||
HtmlCompat.fromHtml(
|
|
||||||
"<b>" + song.title + "</b>",
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setContentText(song.artistName)
|
|
||||||
.setSubText(
|
|
||||||
HtmlCompat.fromHtml(
|
|
||||||
"<b>" + song.albumName + "</b>",
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setOngoing(isPlaying)
|
|
||||||
.setShowWhen(false)
|
|
||||||
.addAction(toggleFavorite)
|
|
||||||
.addAction(previousAction)
|
|
||||||
.addAction(playPauseAction)
|
|
||||||
.addAction(nextAction)
|
|
||||||
|
|
||||||
builder.setStyle(
|
|
||||||
MediaStyle()
|
|
||||||
.setMediaSession(service.mediaSession.sessionToken)
|
|
||||||
.setShowActionsInCompactView(1, 2, 3)
|
|
||||||
)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
if (Build.VERSION.SDK_INT <=
|
|
||||||
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
|
|
||||||
) {
|
|
||||||
builder.color = color
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopped) {
|
|
||||||
return // notification has been stopped before loading was finished
|
|
||||||
}
|
|
||||||
updateNotifyModeAndPostNotification(builder.build())
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildPlayAction(isPlaying: Boolean): NotificationCompat.Action {
|
||||||
|
val playButtonResId =
|
||||||
|
if (isPlaying) R.drawable.ic_pause_white_48dp else R.drawable.ic_play_arrow_white_48dp
|
||||||
|
return NotificationCompat.Action.Builder(
|
||||||
|
playButtonResId,
|
||||||
|
context.getString(R.string.action_play_pause),
|
||||||
|
retrievePlaybackAction(ACTION_TOGGLE_PAUSE)
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildFavoriteAction(isFavorite: Boolean): NotificationCompat.Action {
|
||||||
|
val favoriteResId =
|
||||||
|
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
||||||
|
return NotificationCompat.Action.Builder(
|
||||||
|
favoriteResId,
|
||||||
|
context.getString(R.string.action_toggle_favorite),
|
||||||
|
retrievePlaybackAction(TOGGLE_FAVORITE)
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setPlaying(isPlaying: Boolean) {
|
||||||
|
mActions[2] = buildPlayAction(isPlaying)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateFavorite(song: Song, onUpdate: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
val playlist: PlaylistEntity = MusicUtil.repository.favoritePlaylist()
|
||||||
|
val isFavorite = if (playlist != null) {
|
||||||
|
val songEntity = song.toSongEntity(playlist.playListId)
|
||||||
|
MusicUtil.repository.isFavoriteSong(songEntity).isNotEmpty()
|
||||||
|
} else false
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
mActions[0] = buildFavoriteAction(isFavorite)
|
||||||
|
onUpdate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun retrievePlaybackAction(action: String): PendingIntent {
|
private fun retrievePlaybackAction(action: String): PendingIntent {
|
||||||
val serviceName = ComponentName(service, MusicService::class.java)
|
val serviceName = ComponentName(context, MusicService::class.java)
|
||||||
val intent = Intent(action)
|
val intent = Intent(action)
|
||||||
intent.component = serviceName
|
intent.component = serviceName
|
||||||
return PendingIntent.getService(
|
return PendingIntent.getService(
|
||||||
service, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or
|
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or
|
||||||
if (VersionUtils.hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE
|
if (VersionUtils.hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE
|
||||||
else 0
|
else 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun from(
|
||||||
|
context: Context,
|
||||||
|
notificationManager: NotificationManager,
|
||||||
|
mediaSession: MediaSessionCompat
|
||||||
|
): PlayingNotification {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
createNotificationChannel(context, notificationManager)
|
||||||
|
}
|
||||||
|
return PlayingNotificationImpl(context, mediaSession.sessionToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.service.notification
|
package code.name.monkey.retromusic.service.notification
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -21,6 +23,7 @@ import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Build
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
|
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
|
||||||
|
@ -29,6 +32,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.MainActivity
|
import code.name.monkey.retromusic.activities.MainActivity
|
||||||
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
@ -39,77 +43,66 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil.createBitmap
|
import code.name.monkey.retromusic.util.RetroUtil.createBitmap
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.target.SimpleTarget
|
|
||||||
import com.bumptech.glide.request.target.Target
|
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hemanth S (h4h13).
|
* @author Hemanth S (h4h13).
|
||||||
*/
|
*/
|
||||||
class PlayingNotificationOreo : PlayingNotification() {
|
@SuppressLint("RestrictedApi")
|
||||||
|
class PlayingNotificationOreo(
|
||||||
|
val context: Context
|
||||||
|
) : PlayingNotification(context) {
|
||||||
|
|
||||||
private var target: Target<BitmapPaletteWrapper>? = null
|
private var primaryColor: Int = 0
|
||||||
|
|
||||||
private fun getCombinedRemoteViews(collapsed: Boolean, song: Song): RemoteViews {
|
init {
|
||||||
val remoteViews = RemoteViews(
|
val notificationLayout = getCombinedRemoteViews(true)
|
||||||
service.packageName,
|
val notificationLayoutBig = getCombinedRemoteViews(false)
|
||||||
if (collapsed) R.layout.layout_notification_collapsed else R.layout.layout_notification_expanded
|
|
||||||
)
|
|
||||||
remoteViews.setTextViewText(
|
|
||||||
R.id.appName,
|
|
||||||
service.getString(R.string.app_name) + " • " + song.albumName
|
|
||||||
)
|
|
||||||
remoteViews.setTextViewText(R.id.title, song.title)
|
|
||||||
remoteViews.setTextViewText(R.id.subtitle, song.artistName)
|
|
||||||
linkButtons(remoteViews)
|
|
||||||
return remoteViews
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update() {
|
val action = Intent(context, MainActivity::class.java)
|
||||||
stopped = false
|
|
||||||
val song = service.currentSong
|
|
||||||
val isPlaying = service.isPlaying
|
|
||||||
|
|
||||||
val notificationLayout = getCombinedRemoteViews(true, song)
|
|
||||||
val notificationLayoutBig = getCombinedRemoteViews(false, song)
|
|
||||||
|
|
||||||
val action = Intent(service, MainActivity::class.java)
|
|
||||||
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
|
|
||||||
val clickIntent = PendingIntent
|
val clickIntent = PendingIntent
|
||||||
.getActivity(
|
.getActivity(
|
||||||
service,
|
context,
|
||||||
0,
|
0,
|
||||||
action,
|
action,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
|
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
else 0
|
else 0
|
||||||
)
|
)
|
||||||
val deleteIntent = buildPendingIntent(service, ACTION_QUIT, null)
|
val deleteIntent = buildPendingIntent(context, ACTION_QUIT, null)
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(service, NOTIFICATION_CHANNEL_ID)
|
setSmallIcon(R.drawable.ic_notification)
|
||||||
.setSmallIcon(R.drawable.ic_notification)
|
setContentIntent(clickIntent)
|
||||||
.setContentIntent(clickIntent)
|
setDeleteIntent(deleteIntent)
|
||||||
.setDeleteIntent(deleteIntent)
|
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
priority = NotificationCompat.PRIORITY_MAX
|
||||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
setCustomContentView(notificationLayout)
|
||||||
.setCustomContentView(notificationLayout)
|
setCustomBigContentView(notificationLayoutBig)
|
||||||
.setCustomBigContentView(notificationLayoutBig)
|
setOngoing(true)
|
||||||
.setOngoing(isPlaying)
|
|
||||||
|
|
||||||
val bigNotificationImageSize = service.resources
|
|
||||||
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
|
||||||
service.runOnUiThread {
|
|
||||||
if (target != null) {
|
|
||||||
Glide.with(service).clear(target)
|
|
||||||
}
|
}
|
||||||
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
|
|
||||||
|
private fun getCombinedRemoteViews(collapsed: Boolean): RemoteViews {
|
||||||
|
val remoteViews = RemoteViews(
|
||||||
|
context.packageName,
|
||||||
|
if (collapsed) R.layout.layout_notification_collapsed else R.layout.layout_notification_expanded
|
||||||
|
)
|
||||||
|
linkButtons(remoteViews)
|
||||||
|
return remoteViews
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
|
||||||
|
val bigNotificationImageSize = context.resources
|
||||||
|
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
||||||
|
GlideApp.with(context).asBitmapPalette().songCoverOptions(song)
|
||||||
.load(RetroGlideExtension.getSongModel(song))
|
.load(RetroGlideExtension.getSongModel(song))
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(object : SimpleTarget<BitmapPaletteWrapper>(
|
.into(object : CustomTarget<BitmapPaletteWrapper>(
|
||||||
bigNotificationImageSize,
|
bigNotificationImageSize,
|
||||||
bigNotificationImageSize
|
bigNotificationImageSize
|
||||||
) {
|
) {
|
||||||
|
@ -117,13 +110,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
resource: BitmapPaletteWrapper,
|
resource: BitmapPaletteWrapper,
|
||||||
transition: Transition<in BitmapPaletteWrapper>?
|
transition: Transition<in BitmapPaletteWrapper>?
|
||||||
) {
|
) {
|
||||||
/* val mediaNotificationProcessor = MediaNotificationProcessor(
|
val colors = MediaNotificationProcessor(context, resource.bitmap)
|
||||||
service,
|
|
||||||
service
|
|
||||||
) { i, _ -> update(resource.bitmap, i) }
|
|
||||||
mediaNotificationProcessor.processNotification(resource.bitmap)*/
|
|
||||||
|
|
||||||
val colors = MediaNotificationProcessor(service, resource.bitmap)
|
|
||||||
update(resource.bitmap, colors.backgroundColor)
|
update(resource.bitmap, colors.backgroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,21 +118,24 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
super.onLoadFailed(errorDrawable)
|
super.onLoadFailed(errorDrawable)
|
||||||
update(
|
update(
|
||||||
null,
|
null,
|
||||||
resolveColor(service, R.attr.colorSurface, Color.WHITE)
|
resolveColor(context, R.attr.colorSurface, Color.WHITE)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onLoadCleared(placeholder: Drawable?) {
|
||||||
|
}
|
||||||
|
|
||||||
private fun update(bitmap: Bitmap?, bgColor: Int) {
|
private fun update(bitmap: Bitmap?, bgColor: Int) {
|
||||||
var bgColorFinal = bgColor
|
var bgColorFinal = bgColor
|
||||||
if (bitmap != null) {
|
if (bitmap != null) {
|
||||||
notificationLayout.setImageViewBitmap(R.id.largeIcon, bitmap)
|
contentView.setImageViewBitmap(R.id.largeIcon, bitmap)
|
||||||
notificationLayoutBig.setImageViewBitmap(R.id.largeIcon, bitmap)
|
bigContentView.setImageViewBitmap(R.id.largeIcon, bitmap)
|
||||||
} else {
|
} else {
|
||||||
notificationLayout.setImageViewResource(
|
contentView.setImageViewResource(
|
||||||
R.id.largeIcon,
|
R.id.largeIcon,
|
||||||
R.drawable.default_audio_art
|
R.drawable.default_audio_art
|
||||||
)
|
)
|
||||||
notificationLayoutBig.setImageViewResource(
|
bigContentView.setImageViewResource(
|
||||||
R.id.largeIcon,
|
R.id.largeIcon,
|
||||||
R.drawable.default_audio_art
|
R.drawable.default_audio_art
|
||||||
)
|
)
|
||||||
|
@ -157,106 +147,127 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
if (!VersionUtils.hasS()) {
|
if (!VersionUtils.hasS()) {
|
||||||
if (!PreferenceUtil.isColoredNotification) {
|
if (!PreferenceUtil.isColoredNotification) {
|
||||||
bgColorFinal =
|
bgColorFinal =
|
||||||
resolveColor(service, R.attr.colorPrimary, Color.WHITE)
|
resolveColor(context, R.attr.colorSurface, Color.WHITE)
|
||||||
}
|
}
|
||||||
setBackgroundColor(bgColorFinal)
|
setBackgroundColor(bgColorFinal)
|
||||||
}
|
|
||||||
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))
|
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))
|
||||||
|
}else {
|
||||||
if (stopped) {
|
setNotificationContent(!ColorUtil.isColorLight(context.surfaceColor()))
|
||||||
return // notification has been stopped before loading was finished
|
|
||||||
}
|
}
|
||||||
updateNotifyModeAndPostNotification(builder.build())
|
onUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setBackgroundColor(color: Int) {
|
private fun setBackgroundColor(color: Int) {
|
||||||
notificationLayout.setInt(R.id.image, "setBackgroundColor", color)
|
contentView.setInt(R.id.image, "setBackgroundColor", color)
|
||||||
notificationLayoutBig.setInt(R.id.image, "setBackgroundColor", color)
|
bigContentView.setInt(R.id.image, "setBackgroundColor", color)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setNotificationContent(dark: Boolean) {
|
private fun setNotificationContent(dark: Boolean) {
|
||||||
val primary = MaterialValueHelper.getPrimaryTextColor(service, dark)
|
val primary = MaterialValueHelper.getPrimaryTextColor(context, dark)
|
||||||
val secondary = MaterialValueHelper.getSecondaryTextColor(service, dark)
|
val secondary = MaterialValueHelper.getSecondaryTextColor(context, dark)
|
||||||
|
primaryColor = primary
|
||||||
|
|
||||||
val close = createBitmap(
|
val close = createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
context,
|
||||||
R.drawable.ic_close,
|
R.drawable.ic_close,
|
||||||
primary
|
primary
|
||||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
val prev = createBitmap(
|
val prev = createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
context,
|
||||||
R.drawable.ic_skip_previous_round_white_32dp,
|
R.drawable.ic_skip_previous_round_white_32dp,
|
||||||
primary
|
primary
|
||||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
val next = createBitmap(
|
val next = createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
context,
|
||||||
R.drawable.ic_skip_next_round_white_32dp,
|
R.drawable.ic_skip_next_round_white_32dp,
|
||||||
primary
|
primary
|
||||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
val playPause = createBitmap(
|
val playPause = getPlayPauseBitmap(true)
|
||||||
RetroUtil.getTintedVectorDrawable(
|
|
||||||
service,
|
contentView.setTextColor(R.id.title, primary)
|
||||||
if (isPlaying)
|
contentView.setTextColor(R.id.subtitle, secondary)
|
||||||
R.drawable.ic_pause_white_48dp
|
contentView.setTextColor(R.id.appName, secondary)
|
||||||
else
|
|
||||||
R.drawable.ic_play_arrow_white_48dp, primary
|
contentView.setImageViewBitmap(R.id.action_prev, prev)
|
||||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
contentView.setImageViewBitmap(R.id.action_next, next)
|
||||||
|
contentView.setImageViewBitmap(R.id.action_play_pause, playPause)
|
||||||
|
|
||||||
|
contentView.setTextViewText(
|
||||||
|
R.id.appName,
|
||||||
|
context.getString(R.string.app_name) + " • " + song.albumName
|
||||||
)
|
)
|
||||||
|
contentView.setTextViewText(R.id.title, song.title)
|
||||||
|
contentView.setTextViewText(R.id.subtitle, song.artistName)
|
||||||
|
|
||||||
notificationLayout.setTextColor(R.id.title, primary)
|
|
||||||
notificationLayout.setTextColor(R.id.subtitle, secondary)
|
|
||||||
notificationLayout.setTextColor(R.id.appName, secondary)
|
|
||||||
|
|
||||||
notificationLayout.setImageViewBitmap(R.id.action_prev, prev)
|
bigContentView.setTextColor(R.id.title, primary)
|
||||||
notificationLayout.setImageViewBitmap(R.id.action_next, next)
|
bigContentView.setTextColor(R.id.subtitle, secondary)
|
||||||
notificationLayout.setImageViewBitmap(R.id.action_play_pause, playPause)
|
bigContentView.setTextColor(R.id.appName, secondary)
|
||||||
|
|
||||||
notificationLayoutBig.setTextColor(R.id.title, primary)
|
bigContentView.setImageViewBitmap(R.id.action_quit, close)
|
||||||
notificationLayoutBig.setTextColor(R.id.subtitle, secondary)
|
bigContentView.setImageViewBitmap(R.id.action_prev, prev)
|
||||||
notificationLayoutBig.setTextColor(R.id.appName, secondary)
|
bigContentView.setImageViewBitmap(R.id.action_next, next)
|
||||||
|
bigContentView.setImageViewBitmap(R.id.action_play_pause, playPause)
|
||||||
|
|
||||||
notificationLayoutBig.setImageViewBitmap(R.id.action_quit, close)
|
bigContentView.setTextViewText(
|
||||||
notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev)
|
R.id.appName,
|
||||||
notificationLayoutBig.setImageViewBitmap(R.id.action_next, next)
|
context.getString(R.string.app_name) + " • " + song.albumName
|
||||||
notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause)
|
)
|
||||||
|
bigContentView.setTextViewText(R.id.title, song.title)
|
||||||
|
bigContentView.setTextViewText(R.id.subtitle, song.artistName)
|
||||||
|
|
||||||
notificationLayout.setImageViewBitmap(
|
|
||||||
|
contentView.setImageViewBitmap(
|
||||||
R.id.smallIcon,
|
R.id.smallIcon,
|
||||||
createBitmap(
|
createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
context,
|
||||||
R.drawable.ic_notification,
|
R.drawable.ic_notification,
|
||||||
secondary
|
secondary
|
||||||
), 0.6f
|
), 0.6f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
notificationLayoutBig.setImageViewBitmap(
|
bigContentView.setImageViewBitmap(
|
||||||
R.id.smallIcon,
|
R.id.smallIcon,
|
||||||
createBitmap(
|
createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
context,
|
||||||
R.drawable.ic_notification,
|
R.drawable.ic_notification,
|
||||||
secondary
|
secondary
|
||||||
), 0.6f
|
), 0.6f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stopped) {
|
private fun getPlayPauseBitmap(isPlaying: Boolean): Bitmap {
|
||||||
return // notification has been stopped before loading was finished
|
return createBitmap(
|
||||||
}
|
RetroUtil.getTintedVectorDrawable(
|
||||||
updateNotifyModeAndPostNotification(builder.build())
|
context,
|
||||||
|
if (isPlaying)
|
||||||
|
R.drawable.ic_pause_white_48dp
|
||||||
|
else
|
||||||
|
R.drawable.ic_play_arrow_white_48dp, primaryColor
|
||||||
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setPlaying(isPlaying: Boolean) {
|
||||||
|
getPlayPauseBitmap(isPlaying).also {
|
||||||
|
contentView.setImageViewBitmap(R.id.action_play_pause, it)
|
||||||
|
bigContentView.setImageViewBitmap(R.id.action_play_pause, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateFavorite(song: Song, onUpdate: () -> Unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildPendingIntent(
|
private fun buildPendingIntent(
|
||||||
context: Context, action: String,
|
context: Context, action: String,
|
||||||
|
@ -275,23 +286,34 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
private fun linkButtons(notificationLayout: RemoteViews) {
|
private fun linkButtons(notificationLayout: RemoteViews) {
|
||||||
var pendingIntent: PendingIntent
|
var pendingIntent: PendingIntent
|
||||||
|
|
||||||
val serviceName = ComponentName(service, MusicService::class.java)
|
val serviceName = ComponentName(context, MusicService::class.java)
|
||||||
|
|
||||||
// Previous track
|
// Previous track
|
||||||
pendingIntent = buildPendingIntent(service, ACTION_REWIND, serviceName)
|
pendingIntent = buildPendingIntent(context, ACTION_REWIND, serviceName)
|
||||||
notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent)
|
notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent)
|
||||||
|
|
||||||
// Play and pause
|
// Play and pause
|
||||||
pendingIntent = buildPendingIntent(service, ACTION_TOGGLE_PAUSE, serviceName)
|
pendingIntent = buildPendingIntent(context, ACTION_TOGGLE_PAUSE, serviceName)
|
||||||
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent)
|
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent)
|
||||||
|
|
||||||
// Next track
|
// Next track
|
||||||
pendingIntent = buildPendingIntent(service, ACTION_SKIP, serviceName)
|
pendingIntent = buildPendingIntent(context, ACTION_SKIP, serviceName)
|
||||||
notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent)
|
notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent)
|
||||||
|
|
||||||
// Close
|
// Close
|
||||||
pendingIntent = buildPendingIntent(service, ACTION_QUIT, serviceName)
|
pendingIntent = buildPendingIntent(context, ACTION_QUIT, serviceName)
|
||||||
notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent)
|
notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(
|
||||||
|
context: Context,
|
||||||
|
notificationManager: NotificationManager
|
||||||
|
): PlayingNotification {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
createNotificationChannel(context, notificationManager)
|
||||||
|
}
|
||||||
|
return PlayingNotificationOreo(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue