X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff..269195b3729c1bdc22e9053ee4ebca667ea8549d:/Android/app/src/main/java/com/moiseum/wolnelektury/view/player/service/AudiobookService.java?ds=inline diff --git a/Android/app/src/main/java/com/moiseum/wolnelektury/view/player/service/AudiobookService.java b/Android/app/src/main/java/com/moiseum/wolnelektury/view/player/service/AudiobookService.java new file mode 100755 index 0000000..a95f53f --- /dev/null +++ b/Android/app/src/main/java/com/moiseum/wolnelektury/view/player/service/AudiobookService.java @@ -0,0 +1,286 @@ +/* + * 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.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v4.media.MediaBrowserCompat; +import android.support.v4.media.MediaBrowserServiceCompat; +import android.support.v4.media.MediaDescriptionCompat; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +public class AudiobookService extends MediaBrowserServiceCompat { + + private static final String TAG = AudiobookService.class.getSimpleName(); + + public static final String ACTION_CLEAR_PLAYLIST = "CommandClear"; + public static final String EXTRA_PLAYBACK_CURRENT = "PlaybackCurrent"; + public static final String EXTRA_PLAYBACK_TOTAL = "PlaybackTotal"; + + private MediaSessionCompat mSession; + private PlayerAdapter mPlayback; + private MediaNotificationManager mMediaNotificationManager; + private MediaSessionCallback mCallback; + private boolean mServiceInStartedState; + + @Override + public void onCreate() { + super.onCreate(); + + // Create a new MediaSession. + mSession = new MediaSessionCompat(this, "AudiobookService"); + mCallback = new MediaSessionCallback(); + mSession.setCallback(mCallback); + mSession.setFlags( + MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | + MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS | + MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); + setSessionToken(mSession.getSessionToken()); + + mMediaNotificationManager = new MediaNotificationManager(this); + + mPlayback = new MediaPlayerAdapter(this, new MediaPlayerListener()); + Log.d(TAG, "onCreate: AudiobookService creating MediaSession, and MediaNotificationManager"); + } + + @Override + public void onTaskRemoved(Intent rootIntent) { + super.onTaskRemoved(rootIntent); + stopSelf(); + } + + @Override + public void onDestroy() { + mMediaNotificationManager.onDestroy(); + mPlayback.stop(); + mSession.release(); + Log.d(TAG, "onDestroy: MediaPlayerAdapter stopped, and MediaSession released"); + } + + @Override + public BrowserRoot onGetRoot(@NonNull String clientPackageName, + int clientUid, + Bundle rootHints) { + return new BrowserRoot(AudiobookLibrary.getRoot(), null); + } + + @Override + public void onLoadChildren( + @NonNull final String parentMediaId, + @NonNull final Result> result) { + result.sendResult(AudiobookLibrary.getMediaItems()); + } + + // MediaSession Callback: Transport Controls -> MediaPlayerAdapter + public class MediaSessionCallback extends MediaSessionCompat.Callback { + private final List mPlaylist = new ArrayList<>(); + private int mQueueIndex = -1; + private MediaMetadataCompat mPreparedMedia; + + @Override + public void onCustomAction(String action, Bundle extras) { + if (ACTION_CLEAR_PLAYLIST.equals(action)) { + mPlaylist.clear(); + mQueueIndex = 0; + mSession.setQueue(mPlaylist); + } + } + + @Override + public void onAddQueueItem(MediaDescriptionCompat description) { + mPlaylist.add(new MediaSessionCompat.QueueItem(description, description.hashCode())); + mQueueIndex = (mQueueIndex == -1) ? 0 : mQueueIndex; + mSession.setQueue(mPlaylist); + } + + @Override + public void onRemoveQueueItem(MediaDescriptionCompat description) { + mPlaylist.remove(new MediaSessionCompat.QueueItem(description, description.hashCode())); + mQueueIndex = (mPlaylist.isEmpty()) ? -1 : mQueueIndex; + mSession.setQueue(mPlaylist); + } + + @Override + public void onPrepare() { + if (mQueueIndex < 0 && mPlaylist.isEmpty()) { + // Nothing to play. + return; + } + + final String mediaId = mPlaylist.get(mQueueIndex).getDescription().getMediaId(); + mPreparedMedia = AudiobookLibrary.getMetadata(AudiobookService.this, mediaId); + mSession.setMetadata(mPreparedMedia); + + if (!mSession.isActive()) { + mSession.setActive(true); + } + } + + @Override + public void onPlay() { + if (!isReadyToPlay()) { + // Nothing to play. + return; + } + + if (mPreparedMedia == null) { + onPrepare(); + } + + mPlayback.playFromMedia(mPreparedMedia); + Log.d(TAG, "onPlayFromMediaId: MediaSession active"); + } + + @Override + public void onPause() { + mPlayback.pause(); + } + + @Override + public void onStop() { + mPlayback.stop(); + mSession.setActive(false); + } + + @Override + public void onSkipToNext() { + mQueueIndex = (++mQueueIndex % mPlaylist.size()); + mPreparedMedia = null; + onPlay(); + } + + @Override + public void onSkipToPrevious() { + mQueueIndex = mQueueIndex > 0 ? mQueueIndex - 1 : mPlaylist.size() - 1; + mPreparedMedia = null; + onPlay(); + } + + @Override + public void onSkipToQueueItem(long id) { + mQueueIndex = (int) id; + mPreparedMedia = null; + onPlay(); + } + + @Override + public void onSeekTo(long pos) { + mPlayback.seekTo(pos); + } + + @Override + public void onFastForward() { + mPlayback.fastForward(); + } + + @Override + public void onRewind() { + mPlayback.rewind(); + } + + private boolean isReadyToPlay() { + return (!mPlaylist.isEmpty()); + } + } + + // MediaPlayerAdapter Callback: MediaPlayerAdapter state -> AudiobookService. + public class MediaPlayerListener extends PlaybackInfoListener { + + private final ServiceManager mServiceManager; + + MediaPlayerListener() { + mServiceManager = new ServiceManager(); + } + + @Override + public void onPlaybackStateChange(PlaybackStateCompat state) { + // Report the state to the MediaSession. + mSession.setPlaybackState(state); + + // Manage the started state of this service. + switch (state.getState()) { + case PlaybackStateCompat.STATE_PLAYING: + mServiceManager.moveServiceToStartedState(state); + break; + case PlaybackStateCompat.STATE_PAUSED: + mServiceManager.updateNotificationForPause(state); + break; + case PlaybackStateCompat.STATE_STOPPED: + mServiceManager.moveServiceOutOfStartedState(state); + break; + } + } + + @Override + public void onPlaybackProgress(int current) { + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_PLAYBACK_CURRENT, current); + mSession.setExtras(bundle); + } + + @Override + public void onPlaybackPrepared(int duration) { + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_PLAYBACK_TOTAL, duration); + mSession.setExtras(bundle); + } + + class ServiceManager { + + private void moveServiceToStartedState(PlaybackStateCompat state) { + Notification notification = + mMediaNotificationManager.getNotification( + mPlayback.getCurrentMedia(), state, getSessionToken()); + + if (!mServiceInStartedState) { + ContextCompat.startForegroundService( + AudiobookService.this, + new Intent(AudiobookService.this, AudiobookService.class)); + mServiceInStartedState = true; + } + + startForeground(MediaNotificationManager.NOTIFICATION_ID, notification); + } + + private void updateNotificationForPause(PlaybackStateCompat state) { + stopForeground(false); + Notification notification = + mMediaNotificationManager.getNotification( + mPlayback.getCurrentMedia(), state, getSessionToken()); + mMediaNotificationManager.getNotificationManager() + .notify(MediaNotificationManager.NOTIFICATION_ID, notification); + } + + private void moveServiceOutOfStartedState(PlaybackStateCompat state) { + stopForeground(true); + stopSelf(); + mServiceInStartedState = false; + } + } + + } + +} \ No newline at end of file