diff --git a/src/ch/blinkenlights/android/medialibrary/MediaScanner.java b/src/ch/blinkenlights/android/medialibrary/MediaScanner.java index c6aec0d5..28427c8f 100644 --- a/src/ch/blinkenlights/android/medialibrary/MediaScanner.java +++ b/src/ch/blinkenlights/android/medialibrary/MediaScanner.java @@ -12,16 +12,15 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . */ package ch.blinkenlights.android.medialibrary; import ch.blinkenlights.android.vanilla.R; +import ch.blinkenlights.android.vanilla.NotificationHelper; import android.app.Notification; -import android.app.NotificationManager; - import android.content.Context; import android.content.ContentValues; import android.content.SharedPreferences; @@ -70,6 +69,10 @@ public class MediaScanner implements Handler.Callback { * True if we must do a full cleanup of orphaned entries after the scan finished. */ private boolean mPendingCleanup; + /** + * Our NotificationHelper instance. + */ + private NotificationHelper mNotificationHelper; /** * Timestamp in half-seconds since last notification */ @@ -78,6 +81,8 @@ public class MediaScanner implements Handler.Callback { * The id we are using for the scan notification */ private static final int NOTIFICATION_ID = 56162; + private static final String NOTIFICATION_CHANNEL = "Scanner"; + MediaScanner(Context context, MediaLibraryBackend backend) { mContext = context; @@ -87,6 +92,7 @@ public class MediaScanner implements Handler.Callback { handlerThread.start(); mHandler = new Handler(handlerThread.getLooper(), this); mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VanillaMusicIndexerLock"); + mNotificationHelper = new NotificationHelper(context, NOTIFICATION_CHANNEL, context.getString(R.string.media_stats_progress)); // the content observer to use ContentObserver mObserver = new ContentObserver(null) { @@ -265,7 +271,6 @@ public class MediaScanner implements Handler.Callback { */ private void updateNotification(boolean visible) { MediaLibrary.ScanProgress progress = describeScanProgress(); - NotificationManager manager = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE); if (visible) { int nowTime = (int)(SystemClock.uptimeMillis() / 500); @@ -275,20 +280,20 @@ public class MediaScanner implements Handler.Callback { String title = mContext.getResources().getString(R.string.media_library_scan_running); String content = progress.lastFile; - Notification notification = new Notification.Builder(mContext) + Notification notification = mNotificationHelper.getNewBuilder(mContext) .setProgress(progress.total, progress.seen, false) .setContentTitle(title) .setContentText(content) .setSmallIcon(icon) .setOngoing(true) .getNotification(); // build() is API 16 :-/ - manager.notify(NOTIFICATION_ID, notification); + mNotificationHelper.notify(NOTIFICATION_ID, notification); } if (!mWakeLock.isHeld()) mWakeLock.acquire(); } else { - manager.cancel(NOTIFICATION_ID); + mNotificationHelper.cancel(NOTIFICATION_ID); if (mWakeLock.isHeld()) mWakeLock.release(); diff --git a/src/ch/blinkenlights/android/vanilla/NotificationHelper.java b/src/ch/blinkenlights/android/vanilla/NotificationHelper.java new file mode 100644 index 00000000..e84141df --- /dev/null +++ b/src/ch/blinkenlights/android/vanilla/NotificationHelper.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 Adrian Ulrich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ch.blinkenlights.android.vanilla; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; + +public class NotificationHelper { + /** + * The notification manager instance we are using. + */ + private NotificationManager mNotificationManager; + /** + * The name of the channel to use for these notifications. + */ + private String mChannelId; + + /** + * Creates and returns a new NotificationHelper. + * + * @param context the context to use. + * @param channelId the ID of the notification channel to create. + * @param name the user visible name of the channel. + */ + public NotificationHelper(Context context, String channelId, String name) { + mNotificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE); + mChannelId = channelId; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_DEFAULT); + mNotificationManager.createNotificationChannel(channel); + } + } + + /** + * Returns a new Notification.Builder. + * + * @param context the context to use + */ + public Notification.Builder getNewBuilder(Context context) { + Notification.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder = new Notification.Builder(context, mChannelId); + } else { + builder = new Notification.Builder(context); + } + return builder; + } + + /** + * Retruns a new Notification. + * + * @param context the context to use. + */ + public Notification getNewNotification(Context context) { + return getNewBuilder(context).getNotification(); // build() is API16. + } + + /** + * Post a notification to be shown in the status bar. + * + * @param id the id of this notification. + * @param notification the notification to display. + */ + public void notify(int id, Notification notification) { + mNotificationManager.notify(id, notification); + } + + /** + * Cancels a notification. + * + * @param id the id to cancel + */ + public void cancel(int id) { + mNotificationManager.cancel(id); + } +} diff --git a/src/ch/blinkenlights/android/vanilla/PlaybackService.java b/src/ch/blinkenlights/android/vanilla/PlaybackService.java index 79c85d86..534b7dd0 100644 --- a/src/ch/blinkenlights/android/vanilla/PlaybackService.java +++ b/src/ch/blinkenlights/android/vanilla/PlaybackService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Adrian Ulrich + * Copyright (C) 2012-2017 Adrian Ulrich * Copyright (C) 2010, 2011 Christopher Eby * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,7 +26,6 @@ package ch.blinkenlights.android.vanilla; import ch.blinkenlights.android.medialibrary.MediaLibrary; import android.app.Notification; -import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.app.backup.BackupManager; @@ -96,6 +95,7 @@ public final class PlaybackService extends Service private static final int STATE_VERSION = 6; private static final int NOTIFICATION_ID = 2; + private static final String NOTIFICATION_CHANNEL = "Playback"; /** * Rewind song if we already played more than 2.5 sec @@ -319,6 +319,10 @@ public final class PlaybackService extends Service * {@link PlaybackService#createNotificationAction(SharedPreferences)}. */ private PendingIntent mNotificationAction; + /** + * Notification helper instance. + */ + private NotificationHelper mNotificationHelper; private Looper mLooper; private Handler mHandler; @@ -327,7 +331,6 @@ public final class PlaybackService extends Service private boolean mMediaPlayerInitialized; private boolean mMediaPlayerAudioFxActive; private PowerManager.WakeLock mWakeLock; - private NotificationManager mNotificationManager; private AudioManager mAudioManager; /** * The SensorManager service. @@ -443,7 +446,7 @@ public final class PlaybackService extends Service mBastpUtil = new BastpUtil(); mReadahead = new ReadaheadThread(); - mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + mNotificationHelper = new NotificationHelper(this, NOTIFICATION_CHANNEL, getString(R.string.app_name)); mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); SharedPreferences settings = getSettings(this); @@ -1142,9 +1145,9 @@ public final class PlaybackService extends Service private void updateNotification() { if ((mForceNotificationVisible || mNotificationMode == ALWAYS || mNotificationMode == WHEN_PLAYING && (mState & FLAG_PLAYING) != 0) && mCurrentSong != null) - mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState, mNotificationMode)); + mNotificationHelper.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState, mNotificationMode)); else - mNotificationManager.cancel(NOTIFICATION_ID); + mNotificationHelper.cancel(NOTIFICATION_ID); } /** @@ -2043,7 +2046,7 @@ public final class PlaybackService extends Service } /** - * Create a song notification. Call through the NotificationManager to + * Create a song notification. Call through the NotificationHelper to * display it. * * @param song The Song to display information about. @@ -2101,7 +2104,7 @@ public final class PlaybackService extends Service expanded.setTextViewText(R.id.album, song.album); expanded.setTextViewText(R.id.artist, song.artist); - Notification notification = new Notification(); + Notification notification = mNotificationHelper.getNewNotification(getApplicationContext()); notification.contentView = views; notification.icon = R.drawable.status_icon; notification.flags |= Notification.FLAG_ONGOING_EVENT;