From c80d92b459c4823bd4c741c44d6a331f7812fd74 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Fri, 10 Feb 2017 23:05:52 +0100 Subject: [PATCH] Update how now playing notification is shown. Move all logic to the DownloadServiceImpl as it is not a responsibility of SubsonicTabActivity to do it. Also NotificationCompat.Builder to build notification as now it is a standard way to do it. Signed-off-by: Yahor Berdnikau --- .../activity/SubsonicTabActivity.java | 132 ------------------ .../service/DownloadServiceImpl.java | 121 ++++++++++------ .../src/main/res/layout/notification.xml | 51 ++++--- .../main/res/layout/notification_large.xml | 61 ++++---- 4 files changed, 148 insertions(+), 217 deletions(-) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java index 3189aae2..46b73a67 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java @@ -18,10 +18,8 @@ */ package org.moire.ultrasonic.activity; -import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; -import android.app.Notification; import android.app.NotificationManager; import android.content.Context; import android.content.DialogInterface; @@ -30,11 +28,9 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; -import android.os.Handler; import android.support.v7.app.ActionBar; import android.util.Log; import android.view.KeyEvent; @@ -113,10 +109,7 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen View bookmarksMenuItem; View sharesMenuItem; public static boolean nowPlayingHidden; - public static Entry currentSong; - public Bitmap nowPlayingImage; boolean licenseValid; - NotificationManager notificationManager; private EditText shareDescription; TimeSpanPicker timeSpanPicker; CheckBox hideDialogCheckBox; @@ -167,8 +160,6 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen { menuDrawer.setActiveView(activeView); } - - notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); } @Override @@ -341,129 +332,6 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen } } - public void showNotification(final Handler handler, final Entry song, final DownloadServiceImpl downloadService, final Notification notification, final PlayerState playerState) - { - if (!Util.isNotificationEnabled(this)) - { - return; - } - - new AsyncTask() - { - @SuppressLint("NewApi") - @Override - protected String[] doInBackground(Void... params) - { - Thread.currentThread().setName("showNotification"); - RemoteViews notificationView = notification.contentView; - RemoteViews bigNotificationView = null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - { - bigNotificationView = notification.bigContentView; - } - - if (playerState == PlayerState.PAUSED) - { - setImageViewResourceOnUiThread(notificationView, R.id.control_play, R.drawable.media_start_normal_dark); - - if (bigNotificationView != null) - { - setImageViewResourceOnUiThread(bigNotificationView, R.id.control_play, R.drawable.media_start_normal_dark); - } - } - else if (playerState == PlayerState.STARTED) - { - setImageViewResourceOnUiThread(notificationView, R.id.control_play, R.drawable.media_pause_normal_dark); - - if (bigNotificationView != null) - { - setImageViewResourceOnUiThread(bigNotificationView, R.id.control_play, R.drawable.media_pause_normal_dark); - } - } - - if (currentSong != song) - { - currentSong = song; - - String title = song.getTitle(); - String text = song.getArtist(); - String album = song.getAlbum(); - - try - { - if (nowPlayingImage == null) - { - setImageViewResourceOnUiThread(notificationView, R.id.notification_image, R.drawable.unknown_album); - - if (bigNotificationView != null) - { - setImageViewResourceOnUiThread(bigNotificationView, R.id.notification_image, R.drawable.unknown_album); - } - } - else - { - setImageViewBitmapOnUiThread(notificationView, R.id.notification_image, nowPlayingImage); - - if (bigNotificationView != null) - { - setImageViewBitmapOnUiThread(bigNotificationView, R.id.notification_image, nowPlayingImage); - } - } - } - catch (Exception x) - { - Log.w(TAG, "Failed to get notification cover art", x); - setImageViewResourceOnUiThread(notificationView, R.id.notification_image, R.drawable.unknown_album); - - if (bigNotificationView != null) - { - setImageViewResourceOnUiThread(bigNotificationView, R.id.notification_image, R.drawable.unknown_album); - } - } - - setTextViewTextOnUiThread(notificationView, R.id.trackname, title); - setTextViewTextOnUiThread(notificationView, R.id.artist, text); - setTextViewTextOnUiThread(notificationView, R.id.album, album); - - if (bigNotificationView != null) - { - setTextViewTextOnUiThread(bigNotificationView, R.id.trackname, title); - setTextViewTextOnUiThread(bigNotificationView, R.id.artist, text); - setTextViewTextOnUiThread(bigNotificationView, R.id.album, album); - } - } - - // Send the notification and put the service in the foreground. - handler.post(new Runnable() - { - @Override - public void run() - { - downloadService.startForeground(Constants.NOTIFICATION_ID_PLAYING, notification); - } - }); - - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - public void hidePlayingNotification(final Handler handler, final DownloadServiceImpl downloadService) - { - currentSong = null; - - // Remove notification and remove the service from the foreground - handler.post(new Runnable() - { - @Override - public void run() - { - downloadService.stopForeground(true); - } - }); - } - private void showNowPlaying(final Context context, final DownloadService downloadService, final Entry song, final PlayerState playerState) { if (context == null || downloadService == null || song == null || playerState == null) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java index 7c2e3efa..e02f6e16 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java @@ -36,6 +36,8 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.PowerManager; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; import android.util.Log; import android.widget.RemoteViews; import android.widget.SeekBar; @@ -95,6 +97,8 @@ public class DownloadServiceImpl extends Service implements DownloadService public static final String CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS"; public static final String CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT"; + private static final int NOTIFICATION_ID = 3033; + private final IBinder binder = new SimpleServiceBinder(this); private Looper mediaPlayerLooper; private MediaPlayer mediaPlayer; @@ -111,7 +115,6 @@ public class DownloadServiceImpl extends Service implements DownloadService private final List cleanupCandidates = new ArrayList(); private final Scrobbler scrobbler = new Scrobbler(); private final JukeboxService jukeboxService = new JukeboxService(this); - private Notification notification = new Notification(R.drawable.ic_stat_ultrasonic, null, System.currentTimeMillis()); private DownloadFile currentPlaying; private DownloadFile nextPlaying; @@ -222,19 +225,6 @@ public class DownloadServiceImpl extends Service implements DownloadService audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); setUpRemoteControlClient(); - notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; - notification.contentView = new RemoteViews(this.getPackageName(), R.layout.notification); - Util.linkButtons(this, notification.contentView, false); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - { - notification.bigContentView = new RemoteViews(this.getPackageName(), R.layout.notification_large); - Util.linkButtons(this, notification.bigContentView, false); - } - - Intent notificationIntent = new Intent(this, DownloadActivity.class); - notification.contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); - if (equalizerAvailable) { equalizerController = new EqualizerController(this, mediaPlayer); @@ -311,8 +301,6 @@ public class DownloadServiceImpl extends Service implements DownloadService nextPlayingTask.cancel(); } - notification = null; - Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer.getAudioSessionId()); i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); @@ -724,12 +712,10 @@ public class DownloadServiceImpl extends Service implements DownloadService if (currentPlaying != null) { - if (tabInstance != null) - { - int size = Util.getNotificationImageSize(this); - - tabInstance.nowPlayingImage = FileUtil.getAlbumArtBitmap(this, currentPlaying.getSong(), size, true); - tabInstance.showNotification(handler, currentPlaying.getSong(), this, this.notification, this.playerState); + if (tabInstance != null) { + if (Util.isNotificationEnabled(this)) { + startForeground(NOTIFICATION_ID, buildForegroundNotification()); + } tabInstance.showNowPlaying(); } } @@ -737,8 +723,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { if (tabInstance != null) { - tabInstance.nowPlayingImage = null; - tabInstance.hidePlayingNotification(handler, this); + stopForeground(true); tabInstance.hideNowPlaying(); } } @@ -1246,27 +1231,18 @@ public class DownloadServiceImpl extends Service implements DownloadService UltraSonicAppWidgetProvider4x4.getInstance().notifyChange(this, this, this.playerState == PlayerState.STARTED, false); SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); - Entry song = null; - - if (currentPlaying != null) - { - song = currentPlaying.getSong(); - } - if (show) { if (tabInstance != null) { - if (SubsonicTabActivity.currentSong != song) - { - int size = Util.getNotificationImageSize(this); - tabInstance.nowPlayingImage = FileUtil.getAlbumArtBitmap(this, song, size, true); - } - // Only update notification is player state is one that will change the icon if (this.playerState == PlayerState.STARTED || this.playerState == PlayerState.PAUSED) { - tabInstance.showNotification(handler, song, this, this.notification, this.playerState); + if (Util.isNotificationEnabled(this)) { + final NotificationManagerCompat notificationManager = + NotificationManagerCompat.from(this); + notificationManager.notify(NOTIFICATION_ID, buildForegroundNotification()); + } tabInstance.showNowPlaying(); } } @@ -1275,8 +1251,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { if (tabInstance != null) { - tabInstance.nowPlayingImage = null; - tabInstance.hidePlayingNotification(handler, this); + stopForeground(true); tabInstance.hideNowPlaying(); } } @@ -1398,7 +1373,7 @@ public class DownloadServiceImpl extends Service implements DownloadService } catch (Exception e) { - Log.w("Error getting user information", e); + Log.w(TAG, "Error getting user information", e); } return false; @@ -1417,7 +1392,7 @@ public class DownloadServiceImpl extends Service implements DownloadService } catch (Exception e) { - Log.w("Error getting user information", e); + Log.w(TAG, "Error getting user information", e); } return false; @@ -2096,6 +2071,68 @@ public class DownloadServiceImpl extends Service implements DownloadService } } + private Notification buildForegroundNotification() { + NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + builder.setSmallIcon(R.drawable.ic_stat_ultrasonic); + + builder.setAutoCancel(false); + builder.setOngoing(true); + builder.setWhen(System.currentTimeMillis()); + + RemoteViews contentView = new RemoteViews(this.getPackageName(), R.layout.notification); + Util.linkButtons(this, contentView, false); + RemoteViews bigView = new RemoteViews(this.getPackageName(), R.layout.notification_large); + Util.linkButtons(this, bigView, false); + + builder.setContent(contentView); + + Intent notificationIntent = new Intent(this, DownloadActivity.class); + builder.setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, 0)); + + if (playerState == PlayerState.PAUSED || playerState == PlayerState.IDLE) { + contentView.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark); + bigView.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark); + } else if (playerState == PlayerState.STARTED) { + contentView.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark); + bigView.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark); + } + + final Entry song = currentPlaying.getSong(); + final String title = song.getTitle(); + final String text = song.getArtist(); + final String album = song.getAlbum(); + final int imageSize = Util.getNotificationImageSize(this); + + try { + final Bitmap nowPlayingImage = FileUtil.getAlbumArtBitmap(this, currentPlaying.getSong(), imageSize, true); + if (nowPlayingImage == null) { + contentView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); + bigView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); + } else { + contentView.setImageViewBitmap(R.id.notification_image, nowPlayingImage); + bigView.setImageViewBitmap(R.id.notification_image, nowPlayingImage); + } + } catch (Exception x) { + Log.w(TAG, "Failed to get notification cover art", x); + contentView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); + bigView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); + } + + contentView.setTextViewText(R.id.trackname, title); + bigView.setTextViewText(R.id.trackname, title); + contentView.setTextViewText(R.id.artist, text); + bigView.setTextViewText(R.id.artist, text); + contentView.setTextViewText(R.id.album, album); + bigView.setTextViewText(R.id.album, album); + + Notification notification = builder.build(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + notification.bigContentView = bigView; + } + + return notification; + } + private class BufferTask extends CancellableTask { private final DownloadFile downloadFile; diff --git a/ultrasonic/src/main/res/layout/notification.xml b/ultrasonic/src/main/res/layout/notification.xml index 776603af..d312d89f 100644 --- a/ultrasonic/src/main/res/layout/notification.xml +++ b/ultrasonic/src/main/res/layout/notification.xml @@ -1,63 +1,76 @@ - + android:background="@color/background_color_dark" + > + android:layout_width="64dp" + android:layout_height="64dp" + android:gravity="center" + tools:background="#FF00FF" + /> + android:paddingLeft="12dip" + android:paddingStart="12dp" + > + android:maxLines="1" + tools:text="Track name" + /> + android:maxLines="1" + tools:text="Artist" + /> + android:maxLines="1" + tools:text="Album" + /> + android:gravity="end" + android:orientation="horizontal" + > - @@ -10,20 +12,23 @@ android:id="@+id/notification_image" android:layout_width="128dp" android:layout_height="128dp" - android:gravity="center" /> + android:gravity="center" + tools:background="#ff00ff" + /> + android:paddingBottom="8dip" + > @@ -32,21 +37,24 @@ style="@android:style/TextAppearance.StatusBar.EventContent.Title" android:layout_width="0dip" android:layout_height="wrap_content" - android:layout_gravity="center|left" + android:layout_gravity="center|start" android:layout_weight="1" android:ellipsize="marquee" android:focusable="true" - android:singleLine="true" /> + android:maxLines="1" + tools:text="Track name" + /> + android:src="@drawable/ic_menu_exit_dark" + /> + android:maxLines="1" + tools:text="Artist" + /> + android:maxLines="1" + tools:text="Album" + /> - +