Added Android code
[wl-app.git] / Android / app / src / main / java / com / moiseum / wolnelektury / view / player / service / MediaNotificationManager.java
diff --git a/Android/app/src/main/java/com/moiseum/wolnelektury/view/player/service/MediaNotificationManager.java b/Android/app/src/main/java/com/moiseum/wolnelektury/view/player/service/MediaNotificationManager.java
new file mode 100755 (executable)
index 0000000..b11607b
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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