Java tutorial
/* * Copyright (C) 2014 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.classiqo.nativeandroid_32bitz.playback; import android.content.res.Resources; import android.os.Bundle; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import com.classiqo.nativeandroid_32bitz.R; import com.classiqo.nativeandroid_32bitz.model.MusicProvider; import com.classiqo.nativeandroid_32bitz.utils.LogHelper; import com.classiqo.nativeandroid_32bitz.utils.MediaIDHelper; /** * Created by JsFish-DT on 2017-03-08. */ public class PlaybackManager implements Playback.Callback { private static final String TAG = LogHelper.makeLogTag(PlaybackManager.class); private static final String CUSTOM_ACTION_THUMBS_UP = "com.classiqo.nativeandroid_32bitz.THUMBS_UP"; private MusicProvider mMusicProvider; private QueueManager mQueueManager; private Resources mResources; private Playback mPlayback; private PlaybackServiceCallback mServiceCallback; private MediaSessionCallback mMediaSessionCallback; public PlaybackManager(PlaybackServiceCallback serviceCallback, Resources resources, MusicProvider musicProvider, QueueManager queueManager, Playback playback) { mMusicProvider = musicProvider; mServiceCallback = serviceCallback; mResources = resources; mQueueManager = queueManager; mMediaSessionCallback = new MediaSessionCallback(); mPlayback = playback; mPlayback.setCallback(this); } public Playback getPlayback() { return mPlayback; } public MediaSessionCompat.Callback getMediaSessionCallback() { return mMediaSessionCallback; } public void handlePlayRequest() { LogHelper.d(TAG, "handlePlayRequest: mState = " + mPlayback.getState()); MediaSessionCompat.QueueItem currentMusic = mQueueManager.getCurrentMusic(); if (currentMusic != null) { mServiceCallback.onPlaybackStart(); mPlayback.play(currentMusic); } } public void handlePauseRequest() { LogHelper.d(TAG, "handlePauseRequest: mState = " + mPlayback.getState()); if (mPlayback.isPlaying()) { mPlayback.pause(); mServiceCallback.onPlaybackStop(); } } public void handleStopRequest(String withError) { LogHelper.d(TAG, "handleStopRequest: mState = " + mPlayback.getState() + " error = ", withError); mPlayback.stop(true); mServiceCallback.onPlaybackStop(); updatePlaybackState(withError); } public void updatePlaybackState(String error) { LogHelper.d(TAG, "updatePlaybackState, playback state = " + mPlayback.getState()); long position = PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN; if (mPlayback != null && mPlayback.isConnected()) { position = mPlayback.getCurrentStreamPosition(); } //noinspection ResourceType PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder() .setActions(getAvailableActions()); setCustomAction(stateBuilder); int state = mPlayback.getState(); if (error != null) { stateBuilder.setErrorMessage(error); state = PlaybackStateCompat.STATE_ERROR; } //noinspection ResourceType stateBuilder.setState(state, position, 1.0f, SystemClock.elapsedRealtime()); MediaSessionCompat.QueueItem currentMusic = mQueueManager.getCurrentMusic(); if (currentMusic != null) { stateBuilder.setActiveQueueItemId(currentMusic.getQueueId()); } mServiceCallback.onPlaybackStateUpdated(stateBuilder.build()); if (state == PlaybackStateCompat.STATE_PLAYING || state == PlaybackStateCompat.STATE_PAUSED) { mServiceCallback.onNotificationRequired(); } } private void setCustomAction(PlaybackStateCompat.Builder stateBuilder) { MediaSessionCompat.QueueItem currentMusic = mQueueManager.getCurrentMusic(); if (currentMusic == null) { return; } String mediaId = currentMusic.getDescription().getMediaId(); if (mediaId == null) { return; } String musicId = MediaIDHelper.extractMusicIDFromMediaID(mediaId); int favoriteIcon = mMusicProvider.isFavorite(musicId) ? R.drawable.ic_star_on : R.drawable.ic_star_off; LogHelper.d(TAG, "updatePlaybackState, setting Favorite custom action of music ", musicId, "current favorite = ", mMusicProvider.isFavorite(musicId)); Bundle customActionExtras = new Bundle(); // WearHelper.setShowCustomActionOnWear(customActionExtras, true); stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_THUMBS_UP, mResources.getString(R.string.favorite), favoriteIcon).setExtras(customActionExtras).build()); } private long getAvailableActions() { long actions = PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID | PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_NEXT; if (mPlayback.isPlaying()) { actions |= PlaybackStateCompat.ACTION_PAUSE; } else { actions |= PlaybackStateCompat.ACTION_PLAY; } return actions; } @Override public void onCompletion() { if (mQueueManager.skipQueuePosition(1)) { handlePlayRequest(); mQueueManager.updateMetadata(); } else { handleStopRequest(null); } } @Override public void onPlaybackStatusChanged(int state) { updatePlaybackState(null); } @Override public void onError(String error) { updatePlaybackState(error); } @Override public void setCurrentMediaId(String mediaId) { LogHelper.d(TAG, "setCurrentMediaId", mediaId); mQueueManager.setQueueFromMusic(mediaId); } public void switchToPlayback(Playback playback, boolean resumePlaying) { if (playback == null) { throw new IllegalArgumentException("Playback cannot be null"); } int oldState = mPlayback.getState(); int pos = mPlayback.getCurrentStreamPosition(); String currentMediaId = mPlayback.getCurrentMediaId(); mPlayback.stop(false); playback.setCallback(this); playback.setCurrentStreamPosition(pos < 0 ? 0 : pos); playback.setCurrentMediaId(currentMediaId); playback.start(); mPlayback = playback; switch (oldState) { case PlaybackStateCompat.STATE_BUFFERING: case PlaybackStateCompat.STATE_CONNECTING: case PlaybackStateCompat.STATE_PAUSED: mPlayback.pause(); break; case PlaybackStateCompat.STATE_PLAYING: MediaSessionCompat.QueueItem currentMusic = mQueueManager.getCurrentMusic(); if (resumePlaying && currentMusic != null) { mPlayback.play(currentMusic); } else if (!resumePlaying) { mPlayback.pause(); } else { mPlayback.stop(true); } break; case PlaybackStateCompat.STATE_NONE: break; default: LogHelper.d(TAG, "Default called, Old state is ", oldState); } } private class MediaSessionCallback extends MediaSessionCompat.Callback { @Override public void onPlay() { LogHelper.d(TAG, "play"); if (mQueueManager.getCurrentMusic() == null) { mQueueManager.setRandomQueue(); } handlePlayRequest(); } @Override public void onSkipToQueueItem(long queueId) { LogHelper.d(TAG, "OnSkipToQueueItem: " + queueId); mQueueManager.setCurrentQueueItem(queueId); mQueueManager.updateMetadata(); } @Override public void onSeekTo(long position) { LogHelper.d(TAG, "onSeekTo: ", position); mPlayback.seekTo((int) position); } @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { LogHelper.d(TAG, "playFromMediaId mediaId: ", mediaId, " extras = ", extras); mQueueManager.setQueueFromMusic(mediaId); handlePlayRequest(); } @Override public void onPause() { LogHelper.d(TAG, "pause. current state = " + mPlayback.getState()); handlePauseRequest(); } @Override public void onStop() { LogHelper.d(TAG, "stop. current state = " + mPlayback.getState()); handleStopRequest(null); } @Override public void onSkipToNext() { LogHelper.d(TAG, "skipToNext"); if (mQueueManager.skipQueuePosition(1)) { handlePlayRequest(); } else { handleStopRequest("Cannot skip"); } mQueueManager.updateMetadata(); } @Override public void onSkipToPrevious() { if (mQueueManager.skipQueuePosition(-1)) { handlePlayRequest(); } else { handleStopRequest("Cannot skip"); } mQueueManager.updateMetadata(); } @Override public void onCustomAction(@NonNull String action, Bundle extras) { if (CUSTOM_ACTION_THUMBS_UP.equals(action)) { LogHelper.i(TAG, "onCustomAction: favorite for current track"); MediaSessionCompat.QueueItem currentMusic = mQueueManager.getCurrentMusic(); if (currentMusic != null) { String mediaId = currentMusic.getDescription().getMediaId(); if (mediaId != null) { String musicId = MediaIDHelper.extractMusicIDFromMediaID(mediaId); mMusicProvider.setFavorite(musicId, !mMusicProvider.isFavorite(musicId)); } } updatePlaybackState(null); } else { LogHelper.e(TAG, "Unsupported action: ", action); } } @Override public void onPlayFromSearch(String query, Bundle extras) { LogHelper.d(TAG, "playFromSearch query = ", query, " extras = ", extras); mPlayback.setState(PlaybackStateCompat.STATE_CONNECTING); boolean successSearch = mQueueManager.setQueueFromSearch(query, extras); if (successSearch) { handlePlayRequest(); mQueueManager.updateMetadata(); } else { updatePlaybackState("Could not find music"); } } } public interface PlaybackServiceCallback { void onPlaybackStart(); void onNotificationRequired(); void onPlaybackStop(); void onPlaybackStateUpdated(PlaybackStateCompat newState); } }