--- /dev/null
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.moiseum.wolnelektury.view.player.service;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.app.NotificationCompat.MediaStyle;
+import android.support.v4.media.session.MediaButtonReceiver;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
+import android.util.Log;
+
+import com.bumptech.glide.Glide;
+import com.moiseum.wolnelektury.R;
+import com.moiseum.wolnelektury.view.main.MainActivity;
+
+import java.util.concurrent.ExecutionException;
+
+
+/**
+ * Keeps track of a notification and updates it automatically for a given MediaSession. This is
+ * required so that the music service don't get killed during playback.
+ */
+public class MediaNotificationManager {
+
+ public static final int NOTIFICATION_ID = 412;
+
+ private static final String TAG = MediaNotificationManager.class.getSimpleName();
+ private static final String CHANNEL_ID = "com.moiseum.wolnelektury.audiobookplayer.channel";
+ private static final int REQUEST_CODE = 501;
+
+ private final AudiobookService mService;
+
+ private final NotificationCompat.Action mPlayAction;
+ private final NotificationCompat.Action mPauseAction;
+ private final NotificationCompat.Action mNextAction;
+ private final NotificationCompat.Action mPrevAction;
+ private final NotificationManager mNotificationManager;
+
+ public MediaNotificationManager(AudiobookService service) {
+ mService = service;
+
+ mNotificationManager =
+ (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ mPlayAction =
+ new NotificationCompat.Action(
+ R.drawable.ic_play_arrow_white_24dp,
+ mService.getString(R.string.label_play),
+ MediaButtonReceiver.buildMediaButtonPendingIntent(
+ mService,
+ PlaybackStateCompat.ACTION_PLAY));
+ mPauseAction =
+ new NotificationCompat.Action(
+ R.drawable.ic_pause_white_24dp,
+ mService.getString(R.string.label_pause),
+ MediaButtonReceiver.buildMediaButtonPendingIntent(
+ mService,
+ PlaybackStateCompat.ACTION_PAUSE));
+ mNextAction =
+ new NotificationCompat.Action(
+ R.drawable.ic_skip_next_white_24dp,
+ mService.getString(R.string.label_next),
+ MediaButtonReceiver.buildMediaButtonPendingIntent(
+ mService,
+ PlaybackStateCompat.ACTION_SKIP_TO_NEXT));
+ mPrevAction =
+ new NotificationCompat.Action(
+ R.drawable.ic_skip_previous_white_24dp,
+ mService.getString(R.string.label_previous),
+ MediaButtonReceiver.buildMediaButtonPendingIntent(
+ mService,
+ PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS));
+
+ // Cancel all notifications to handle the case where the Service was killed and
+ // restarted by the system.
+ mNotificationManager.cancelAll();
+ }
+
+ public void onDestroy() {
+ Log.d(TAG, "onDestroy: ");
+ }
+
+ public NotificationManager getNotificationManager() {
+ return mNotificationManager;
+ }
+
+ public Notification getNotification(MediaMetadataCompat metadata,
+ @NonNull PlaybackStateCompat state,
+ MediaSessionCompat.Token token) {
+ boolean isPlaying = state.getState() == PlaybackStateCompat.STATE_PLAYING;
+ MediaDescriptionCompat description = metadata.getDescription();
+ NotificationCompat.Builder builder =
+ buildNotification(state, token, isPlaying, description);
+ return builder.build();
+ }
+
+ private NotificationCompat.Builder buildNotification(@NonNull PlaybackStateCompat state,
+ MediaSessionCompat.Token token,
+ boolean isPlaying,
+ MediaDescriptionCompat description) {
+
+ // Create the (mandatory) notification channel when running on Android Oreo.
+ if (isAndroidOOrHigher()) {
+ createChannel();
+ }
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mService, CHANNEL_ID);
+ builder.setStyle(
+ new MediaStyle()
+ .setMediaSession(token)
+ .setShowActionsInCompactView(0, 1, 2)
+ // For backwards compatibility with Android L and earlier.
+ .setShowCancelButton(true)
+ .setCancelButtonIntent(
+ MediaButtonReceiver.buildMediaButtonPendingIntent(
+ mService,
+ PlaybackStateCompat.ACTION_STOP)))
+ .setColor(ContextCompat.getColor(mService, R.color.colorAccent))
+ .setSmallIcon(R.drawable.ic_notification_player)
+ // Pending intent that is fired when user clicks on notification.
+ .setContentIntent(createContentIntent())
+ // Title - Usually Song name.
+ .setContentTitle(description.getTitle())
+ // Subtitle - Usually Artist name.
+ .setContentText(description.getSubtitle())
+// .setLargeIcon(AudiobookLibrary.getAlbumBitmap(mService, description.getMediaId()))
+ // When notification is deleted (when playback is paused and notification can be
+ // deleted) fire MediaButtonPendingIntent with ACTION_STOP.
+ .setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(
+ mService, PlaybackStateCompat.ACTION_STOP))
+ // Show controls on lock screen even when user hides sensitive content.
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+
+ // If skip to next action is enabled.
+ if ((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) {
+ builder.addAction(mPrevAction);
+ }
+
+ builder.addAction(isPlaying ? mPauseAction : mPlayAction);
+
+ // If skip to prev action is enabled.
+ if ((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) {
+ builder.addAction(mNextAction);
+ }
+
+ return builder;
+ }
+
+ // Does nothing on versions of Android earlier than O.
+ @RequiresApi(Build.VERSION_CODES.O)
+ private void createChannel() {
+ if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
+ // The user-visible name of the channel.
+ CharSequence name = "MediaSession";
+ // The user-visible description of the channel.
+ String description = "MediaSession and MediaPlayer";
+ int importance = NotificationManager.IMPORTANCE_LOW;
+ NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
+ // Configure the notification channel.
+ mChannel.setDescription(description);
+ mChannel.enableLights(true);
+ // Sets the notification light color for notifications posted to this
+ // channel, if the device supports this feature.
+ mChannel.setLightColor(Color.RED);
+ mChannel.enableVibration(true);
+ mChannel.setVibrationPattern(
+ new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
+ mNotificationManager.createNotificationChannel(mChannel);
+ Log.d(TAG, "createChannel: New channel created");
+ } else {
+ Log.d(TAG, "createChannel: Existing channel reused");
+ }
+ }
+
+ private boolean isAndroidOOrHigher() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ }
+
+ private PendingIntent createContentIntent() {
+ Intent openUI = new Intent(mService, MainActivity.class);
+ openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ return PendingIntent.getActivity(
+ mService, REQUEST_CODE, openUI, PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+}
\ No newline at end of file