Java tutorial
package com.iamplus.musicplayer; /* * Copyright (C) 2011 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. */ import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import android.app.PendingIntent; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.media.AudioManager; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.media.RemoteControlClient; import android.os.Binder; import android.os.IBinder; import android.os.Messenger; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.provider.MediaStore; import android.provider.MediaStore.Audio.Media; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.widget.Toast; import com.iamplus.musicplayer.MusicRetriever.e_play_mode; public class MusicService extends Service implements OnCompletionListener, OnPreparedListener, OnErrorListener, MusicFocusable { // The tag we put on debug messages final static String TAG = "iamplusMusicPlayerService"; // These are the Intent actions that we are prepared to handle. Notice that the fact these // constants exist in our class is a mere convenience: what really defines the actions our // service can handle are the <action> tags in the <intent-filters> tag for our service in // AndroidManifest.xml. public static final String ACTION_TOGGLE_PLAYBACK = "com.iamplus.musicplayer.action.TOGGLE_PLAYBACK"; public static final String ACTION_PLAY = "com.iamplus.musicplayer.action.PLAY"; public static final String ACTION_PAUSE = "com.iamplus.musicplayer.action.PAUSE"; public static final String ACTION_STOP = "com.iamplus.musicplayer.action.STOP"; public static final String ACTION_SKIP = "com.iamplus.musicplayer.action.SKIP"; public static final String ACTION_REWIND = "com.iamplus.musicplayer.action.REWIND"; public static final String ACTION_URL = "com.iamplus.musicplayer.action.URL"; public static final String ACTION_SEARCH_PLAY = "com.iamplus.musicplayer.action.SEARCH_PLAY"; public static final String ACTION_REPEAT_ON = "com.iamplus.musicplayer.action.REPEAT_ON"; public static final String ACTION_REPEAT_OFF = "com.iamplus.musicplayer.action.REPEAT_OFF"; public static final String ACTION_SHUFFLE_ON = "com.iamplus.musicplayer.action.SHUFFLE_ON"; public static final String ACTION_SHUFFLE_OFF = "com.iamplus.musicplayer.action.SHUFFLE_OFF"; /** * Local Broadcasts for Playback change notifications. */ public static final String MUSIC_BROAD_CAST_PLAYBACK_STARTED = "PlaybackStarted"; public static final String MUSIC_BROAD_CAST_PLAYBACK_STOPPED = "PlaybackStopped"; public static final String MUSIC_BROAD_CAST_PLAYBACK_ERROR = "PlaybackError"; public static final String MUSIC_BROAD_CAST_PLAYBACK_SKIP = "PlaybackSkip"; public static final String MUSIC_BROAD_CAST_PLAYBACK_PREV = "PlaybackPrev"; // The volume we set the media player to when we lose audio focus, but are allowed to reduce // the volume instead of stopping playback. public static final float DUCK_VOLUME = 0.1f; // our media player MediaPlayer mPlayer = null; // our AudioFocusHelper object, if it's available (it's available on SDK level >= 8) // If not available, this will be null. Always check for null before using! AudioFocusHelper mAudioFocusHelper = null; // indicates the state our service: enum State { Stopped, // media player is stopped and not prepared to play Preparing, // media player is preparing... Playing, // playback active (media player ready!). (but the media player may actually be // paused in this state if we don't have audio focus. But we stay in this state // so that we know we have to resume playback once we get focus back) Paused // playback paused (media player ready!) }; State mState = State.Stopped; enum PauseReason { UserRequest, // paused by user request FocusLoss, // paused because of audio focus loss }; // why did we pause? (only relevant if mState == State.Paused) PauseReason mPauseReason = PauseReason.UserRequest; // do we have audio focus? enum AudioFocus { NoFocusNoDuck, // we don't have audio focus, and can't duck NoFocusCanDuck, // we don't have focus, but can play at a low volume ("ducking") Focused // we have full audio focus } AudioFocus mAudioFocus = AudioFocus.NoFocusNoDuck; // title of the song we are currently playing //String mSongTitle = ""; // whether the song we are playing is streaming from the network boolean mIsStreaming = false; // Wifi lock that we hold when streaming files from the internet, in order to prevent the // device from shutting off the Wifi radio //WifiLock mWifiLock; private WakeLock mWakeLock; // The ID we use for the notification (the onscreen alert that appears at the notification // area at the top of the screen as an icon -- and as text as well if the user expands the // notification area). final int NOTIFICATION_ID = 1; // our RemoteControlClient object, which will use remote control APIs available in // SDK level >= 14, if they're available. RemoteControlClientCompat mRemoteControlClientCompat; // Dummy album art we will pass to the remote control (if the APIs are available). //Bitmap mDummyAlbumArt; // The component name of MusicIntentReceiver, for use with media button and remote control // APIs ComponentName mMediaButtonReceiverComponent; AudioManager mAudioManager; //NotificationManager mNotificationManager; //Notification mNotification = null; //The current playing item MediaItem mCurrentPlayingItem; public interface PlayerEventListener { void onPlayerReady(); void onPlaybackCompleted(); void onPlayPauseStateChanged(); void onPlayBackError(Playback_Error errorcode); } public enum Playback_Error { Playback_Error_Invalid_file, Playback_Error_No_Audio_focus } private final Set<Messenger> clients = new HashSet<Messenger>(); PlayerEventListener mPlayerEventListener; public class MusicServiceBinder extends Binder { public MusicService getPlayerService() { return MusicService.this; } public void register(Messenger messenger) { clients.add(messenger); } public void unregister(Messenger messenger) { clients.remove(messenger); } } Binder musicServiceBinder = new MusicServiceBinder(); private boolean mPausePlayback = false; public void setPlayerEventListener(PlayerEventListener list) { mPlayerEventListener = list; } /** * Makes sure the media player exists and has been reset. This will create the media player * if needed, or reset the existing media player if one already exists. */ void createMediaPlayerIfNeeded() { if (mPlayer == null) { mPlayer = new MediaPlayer(); // Make sure the media player will acquire a wake-lock while playing. If we don't do // that, the CPU might go to sleep while the song is playing, causing playback to stop. // // Remember that to use this, we have to declare the android.permission.WAKE_LOCK // permission in AndroidManifest.xml. mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); // we want the media player to notify us when it's ready preparing, and when it's done // playing: mPlayer.setOnPreparedListener(this); mPlayer.setOnCompletionListener(this); mPlayer.setOnErrorListener(this); } else mPlayer.reset(); } @Override public void onCreate() { Log.i(TAG, "debug: Creating service"); // Create the Wifi lock (this does not acquire the lock, this just creates it) // mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)) // .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock"); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); mWakeLock.setReferenceCounted(false); //mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); // create the Audio Focus Helper, if the Audio Focus feature is available (SDK 8 or above) if (android.os.Build.VERSION.SDK_INT >= 8) mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this); else mAudioFocus = AudioFocus.Focused; // no focus feature, so we always "have" audio focus //mDummyAlbumArt = BitmapFactory.decodeResource(getResources(), R.drawable.albumart_mp_unknown); mMediaButtonReceiverComponent = new ComponentName(this, MusicIntentReceiver.class); e_play_mode emode = MusicRetriever.getPlayModePref(this, e_play_mode.e_play_mode_normal); MusicRetriever.getInstance().setPlayMode(emode); } /** * Called when we receive an Intent. When we receive an intent sent to us via startService(), * this is the method that gets called. So here we react appropriately depending on the * Intent's action, which specifies what is being requested of us. */ @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if (action != null) { if (action.equals(ACTION_TOGGLE_PLAYBACK)) processTogglePlaybackRequest(); else if (action.equals(ACTION_PLAY)) processPlayRequest(); else if (action.equals(ACTION_PAUSE)) processPauseRequest(); else if (action.equals(ACTION_SKIP)) processSkipRequest(); else if (action.equals(ACTION_STOP)) processStopRequest(); else if (action.equals(ACTION_REWIND)) processRewindRequest(); else if (action.equals(ACTION_URL)) processAddRequest(intent); else if (action.equals(ACTION_SHUFFLE_OFF)) processShuffleOff(); else if (action.equals(ACTION_SHUFFLE_ON)) processShuffleOn(); else if (action.equals(ACTION_REPEAT_ON)) processRepeatOff(); else if (action.equals(ACTION_REPEAT_OFF)) processRepeatOn(); } return START_NOT_STICKY; // Means we started the service, but don't want it to // restart in case it's killed. } private void processShuffleOn() { MusicRetriever.getInstance().setPlayMode(e_play_mode.e_play_mode_shuffle); } private void processRepeatOn() { MusicRetriever.getInstance().setPlayMode(e_play_mode.e_play_mode_repeat); } private void processRepeatOff() { MusicRetriever.getInstance().setPlayMode(e_play_mode.e_play_mode_normal); } private void processShuffleOff() { MusicRetriever.getInstance().setPlayMode(e_play_mode.e_play_mode_normal); } void processTogglePlaybackRequest() { //If no audio focus return if (mAudioFocus != AudioFocus.Focused) { tryToGetAudioFocus(); if (mAudioFocus != AudioFocus.Focused) { Toast.makeText(getApplicationContext(), R.string.audio_focus_unavailable, Toast.LENGTH_SHORT) .show(); return; } } if (mState == State.Paused) { // If we're paused, just continue playback and restore the 'foreground service' state. mState = State.Playing; //setUpAsForeground(mSongTitle + " (playing)"); configAndStartMediaPlayer(); // Tell any remote controls that our playback state is 'playing'. if (mRemoteControlClientCompat != null) { mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); } } else if (mState == State.Stopped) { processPlayRequest(); } else { processPauseRequest(); } if (mPlayerEventListener != null) { mPlayerEventListener.onPlayPauseStateChanged(); } } void processPlayRequest() { tryToGetAudioFocus(); if (mAudioFocus == AudioFocus.Focused) { startPlayback(); // Tell any remote controls that our playback state is 'playing'. if (mRemoteControlClientCompat != null) { mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); } if (mPlayerEventListener != null) { mPlayerEventListener.onPlayPauseStateChanged(); } mWakeLock.acquire(); LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(MUSIC_BROAD_CAST_PLAYBACK_STARTED)); } else { Toast.makeText(getApplicationContext(), R.string.audio_focus_unavailable, Toast.LENGTH_LONG).show(); } } void processPauseRequest() { if (mState == State.Playing) { // Pause media player and cancel the 'foreground service' state. mState = State.Paused; mPlayer.pause(); relaxResources(false); // while paused, we always retain the MediaPlayer // do not give up audio focus if (mWakeLock.isHeld()) mWakeLock.release(); } // Tell any remote controls that our playback state is 'paused'. if (mRemoteControlClientCompat != null) { mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED); } } //Set the playback position void setPlaybackPosition(int seconds) { if (mState == State.Playing || mState == State.Paused) mPlayer.seekTo(seconds * 1000); } void processRewindRequest() { if (mState == State.Playing || mState == State.Paused) { tryToGetAudioFocus(); playPrevSong(null, true); LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(MUSIC_BROAD_CAST_PLAYBACK_PREV)); } } void processSkipRequest() { if (mState == State.Playing || mState == State.Paused) { tryToGetAudioFocus(); playNextSong(null, true); LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(MUSIC_BROAD_CAST_PLAYBACK_SKIP)); } } void processStopRequest() { processStopRequest(false); LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(MUSIC_BROAD_CAST_PLAYBACK_STOPPED)); } void processStopRequest(boolean force) { if (mState == State.Playing || mState == State.Paused || force) { mState = State.Stopped; // let go of all resources... relaxResources(true); giveUpAudioFocus(); // Tell any remote controls that our playback state is 'paused'. if (mRemoteControlClientCompat != null) { mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); } // service is no longer necessary. Will be started again if needed. stopSelf(); if (mWakeLock.isHeld()) mWakeLock.release(); if (mPlayerEventListener != null) { mPlayerEventListener.onPlaybackCompleted(); } } } /** * Releases resources used by the service for playback. This includes the "foreground service" * status and notification, the wake locks and possibly the MediaPlayer. * * @param releaseMediaPlayer Indicates whether the Media Player should also be released or not */ void relaxResources(boolean releaseMediaPlayer) { // stop and release the Media Player, if it's available if (releaseMediaPlayer && mPlayer != null) { mPlayer.reset(); mPlayer.release(); mPlayer = null; // stop being a foreground service stopForeground(true); } // we can also release the Wifi lock, if we're holding it //if (mWifiLock.isHeld()) mWifiLock.release(); } void giveUpAudioFocus() { if (mAudioFocus == AudioFocus.Focused && mAudioFocusHelper != null && mAudioFocusHelper.abandonFocus()) mAudioFocus = AudioFocus.NoFocusNoDuck; } /** * Reconfigures MediaPlayer according to audio focus settings and starts/restarts it. This * method starts/restarts the MediaPlayer respecting the current audio focus state. So if * we have focus, it will play normally; if we don't have focus, it will either leave the * MediaPlayer paused or set it to a low volume, depending on what is allowed by the * current focus settings. This method assumes mPlayer != null, so if you are calling it, * you have to do so from a context where you are sure this is the case. */ void configAndStartMediaPlayer() { if (mAudioFocus == AudioFocus.NoFocusNoDuck) { // If we don't have audio focus and can't duck, we have to pause, even if mState // is State.Playing. But we stay in the Playing state so that we know we have to resume // playback once we get the focus back. if (mPlayer.isPlaying()) mPlayer.pause(); return; } else if (mAudioFocus == AudioFocus.NoFocusCanDuck) mPlayer.setVolume(DUCK_VOLUME, DUCK_VOLUME); // we'll be relatively quiet else mPlayer.setVolume(1.0f, 1.0f); // we can be loud if (!mPlayer.isPlaying()) mPlayer.start(); } void processAddRequest(Intent intent) { if (mState == State.Playing || mState == State.Paused || mState == State.Stopped) { Log.i(TAG, "Playing from URL/path: " + intent.getData().toString()); tryToGetAudioFocus(); playNextSong(intent.getData().toString(), true); } } void tryToGetAudioFocus() { if (mAudioFocus != AudioFocus.Focused && mAudioFocusHelper != null && mAudioFocusHelper.requestFocus()) { mAudioFocus = AudioFocus.Focused; } } private ArrayList<MediaItem> getAllSongs() { String[] projection = new String[] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ALBUM_ID, //MediaStore.Audio.Media.DURATION, }; String[] selectionArgs = null; String sortOrder = Media.DEFAULT_SORT_ORDER; String selection = null; Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder); if (cursor != null) { if (!cursor.moveToFirst()) { return null; } ArrayList<MediaItem> songlist = new ArrayList<MediaItem>(); // retrieve the indices of the columns where the ID, title, etc. of the song are int artistColumn = cursor.getColumnIndex(Media.ARTIST); int titleColumn = cursor.getColumnIndex(Media.TITLE); int idcolumn = cursor.getColumnIndex(Media._ID); int albumcolum = cursor.getColumnIndex(Media.ALBUM); int albumidcolum = cursor.getColumnIndex(Media.ALBUM_ID); //int duration = cursor.getColumnIndex(Media.DURATION); // add each song to mAlbumList do { MediaItem item = new MediaItem(); item.setSongId(cursor.getLong(idcolumn)); item.setTitle(cursor.getString(titleColumn)); item.setAlbum(cursor.getString(albumcolum)); item.setArtist(cursor.getString(artistColumn)); item.setAlbumid(cursor.getLong(albumidcolum)); songlist.add(item); } while (cursor.moveToNext()); cursor.close(); return songlist; } else { return null; } } private void startPlayback() { try { MediaItem playingItem = null; mIsStreaming = false; // playing a locally available song playingItem = MusicRetriever.getInstance().getCurrentSong(); if (playingItem == null) { //Get all songs if the current list is empty MusicRetriever.getInstance().setSonglist(getAllSongs(), 0); MusicRetriever.getInstance().setPlayMode(e_play_mode.e_play_mode_shuffle); playingItem = MusicRetriever.getInstance().getCurrentSong(); if (playingItem == null) { processStopRequest(true); // stop everything! return; } } mCurrentPlayingItem = playingItem; // set the source of the media player a a content URI createMediaPlayerIfNeeded(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.setDataSource(getApplicationContext(), playingItem.getURI()); // starts preparing the media player in the background. When it's done, it will call // our OnPreparedListener (that is, the onPrepared() method on this class, since we set // the listener to 'this'). // // Until the media player is prepared, we *cannot* call start() on it! mPlayer.prepareAsync(); // If we are streaming from the internet, we want to hold a Wifi lock, which prevents // the Wifi radio from going to sleep while the song is playing. If, on the other hand, // we are *not* streaming, we want to release the lock if we were holding it before. // if (mIsStreaming) mWifiLock.acquire(); // else if (mWifiLock.isHeld()) mWifiLock.release(); } catch (IOException ex) { Log.e(TAG, "IOException playing first song: " + ex.getMessage()); //ex.printStackTrace(); Toast.makeText(getApplicationContext(), R.string.invalid_file_track, Toast.LENGTH_LONG).show(); //Stop Playback processStopRequest(); return; } //mSongTitle = mCurrentPlayingItem.getTitle(); //setUpAsForeground(mSongTitle + " (loading)"); // Use the media button APIs (if available) to register ourselves for media button // events MediaButtonHelper.registerMediaButtonEventReceiverCompat(mAudioManager, mMediaButtonReceiverComponent); // // Use the remote control APIs (if available) to set the playback state // if (mRemoteControlClientCompat == null) { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); intent.setComponent(mMediaButtonReceiverComponent); mRemoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this /*context*/, 0 /*requestCode, ignored*/, intent /*intent*/, 0 /*flags*/)); RemoteControlHelper.registerRemoteControlClient(mAudioManager, mRemoteControlClientCompat); } mRemoteControlClientCompat.setTransportControlFlags( RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_NEXT | RemoteControlClient.FLAG_KEY_MEDIA_STOP); updateRemoteControlPlayingState(); } public Boolean isPlaying() { return (mState == State.Playing); } public Boolean isPlayerInitialised() { return (mState == State.Playing) || (mState == State.Paused); } //The total duration of the file being played public int getTotalDuration() { if (mState == State.Playing || mState == State.Paused) { return mPlayer.getDuration() / 1000; } return 0; } //The the elapsed time. public int getCurrentDuration() { if (mState == State.Playing || mState == State.Paused) { return mPlayer.getCurrentPosition() / 1000; } return 0; } // Returns the current playing song item public MediaItem getCurrentPlayingItem() { if (mState == State.Playing || mState == State.Paused) return mCurrentPlayingItem; else if (mState == State.Stopped) { MusicRetriever.getInstance().reset(); mCurrentPlayingItem = MusicRetriever.getInstance().getCurrentSong(); return mCurrentPlayingItem; } else return null; } /** * Starts playing the next song. If manualUrl is null, the next song will be randomly selected * from our Media Retriever (that is, it will be a random song in the user's device). If * manualUrl is non-null, then it specifies the URL or path to the song that will be played * next. */ void playPrevSong(String manualUrl, Boolean userAction) { mState = State.Stopped; relaxResources(false); // release everything except MediaPlayer try { MediaItem playingItem = null; if (manualUrl != null) { // set the source of the media player to a manual URL or path createMediaPlayerIfNeeded(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.setDataSource(manualUrl); mIsStreaming = manualUrl.startsWith("http:") || manualUrl.startsWith("https:"); } else { mIsStreaming = false; // playing a locally available song playingItem = MusicRetriever.getInstance().getPrevSong(); if (playingItem == null) { MusicRetriever.getInstance().reset(); playingItem = MusicRetriever.getInstance().getCurrentSong(); } mCurrentPlayingItem = playingItem; // set the source of the media player a a content URI createMediaPlayerIfNeeded(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.setDataSource(getApplicationContext(), playingItem.getURI()); } // starts preparing the media player in the background. When it's done, it will call // our OnPreparedListener (that is, the onPrepared() method on this class, since we set // the listener to 'this'). // // Until the media player is prepared, we *cannot* call start() on it! mPlayer.prepareAsync(); // If we are streaming from the internet, we want to hold a Wifi lock, which prevents // the Wifi radio from going to sleep while the song is playing. If, on the other hand, // we are *not* streaming, we want to release the lock if we were holding it before. // if (mIsStreaming) mWifiLock.acquire(); // else if (mWifiLock.isHeld()) mWifiLock.release(); updateRemoteControlPlayingState(); } catch (IOException ex) { Log.e("MusicService", "IOException playing next song: " + ex.getMessage()); ex.printStackTrace(); Toast.makeText(getApplicationContext(), R.string.invalid_file_track, Toast.LENGTH_LONG).show(); processStopRequest(); } } private void updateRemoteControlPlayingState() { // Tell any remote controls that our playback state is 'Playing'. if (mRemoteControlClientCompat != null) { mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); // Update the remote controls //Bitmap bitmap = MediaAlbumsAdaptor.getAlbumArtwork(getApplicationContext(), mCurrentPlayingItem.getAlbumid(), true); mRemoteControlClientCompat.editMetadata(true) .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, mCurrentPlayingItem.getArtist()) .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, mCurrentPlayingItem.getAlbum()) .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, mCurrentPlayingItem.getTitle()) .putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, mCurrentPlayingItem.getDuration()) .apply(); //.putBitmap(RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK,bitmap).apply(); Log.d(TAG, "Setting Remote Control Meta data **** Start"); Log.d(TAG, "Title = " + mCurrentPlayingItem.getTitle()); Log.d(TAG, "Album = " + mCurrentPlayingItem.getAlbum()); Log.d(TAG, "Artist = " + mCurrentPlayingItem.getArtist()); Log.d(TAG, "Duration = " + mCurrentPlayingItem.getDuration()); //Log.d(TAG, "Bitmap = " + bitmap); Log.d(TAG, "Setting Remote Control Meta data **** End"); } } /** * Starts playing the next song. If manualUrl is null, the next song will be randomly selected * from our Media Retriever (that is, it will be a random song in the user's device). If * manualUrl is non-null, then it specifies the URL or path to the song that will be played * next. */ void playNextSong(String manualUrl, Boolean userAction) { mState = State.Stopped; relaxResources(false); // release everything except MediaPlayer try { MediaItem playingItem = null; if (manualUrl != null) { // set the source of the media player to a manual URL or path createMediaPlayerIfNeeded(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.setDataSource(manualUrl); mIsStreaming = manualUrl.startsWith("http:") || manualUrl.startsWith("https:"); } else { mIsStreaming = false; // playing a locally available song playingItem = MusicRetriever.getInstance().getNextSong(); if (playingItem == null) { MusicRetriever.getInstance().reset(); playingItem = MusicRetriever.getInstance().getCurrentSong(); if (!userAction) { /** * Pause playback if end of playlist */ mPausePlayback = true; } } mCurrentPlayingItem = playingItem; // set the source of the media player a a content URI createMediaPlayerIfNeeded(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.setDataSource(getApplicationContext(), playingItem.getURI()); } // starts preparing the media player in the background. When it's done, it will call // our OnPreparedListener (that is, the onPrepared() method on this class, since we set // the listener to 'this'). // // Until the media player is prepared, we *cannot* call start() on it! mPlayer.prepareAsync(); // If we are streaming from the internet, we want to hold a Wifi lock, which prevents // the Wifi radio from going to sleep while the song is playing. If, on the other hand, // we are *not* streaming, we want to release the lock if we were holding it before. // if (mIsStreaming) mWifiLock.acquire(); // else if (mWifiLock.isHeld()) mWifiLock.release(); updateRemoteControlPlayingState(); } catch (IOException ex) { Log.e("MusicService", "IOException playing next song: " + ex.getMessage()); ex.printStackTrace(); Toast.makeText(getApplicationContext(), R.string.invalid_file_track, Toast.LENGTH_LONG).show(); processStopRequest(); } } /** Called when media player is done playing current song. */ public void onCompletion(MediaPlayer player) { // The media player finished playing the current song, so we go ahead and start the next. playNextSong(null, false); } /** Called when media player is done preparing. */ public void onPrepared(MediaPlayer player) { // The media player is done preparing. That means we can start playing! mState = State.Playing; // updateNotification(mSongTitle + " (playing)"); configAndStartMediaPlayer(); if (mPlayerEventListener != null) { mPlayerEventListener.onPlayerReady(); } if (mPausePlayback) { processPauseRequest(); mPausePlayback = false; if (mPlayerEventListener != null) { mPlayerEventListener.onPlayPauseStateChanged(); } } } /** Updates the notification. */ void updateNotification(String text) { //mNotificationManager.notify(NOTIFICATION_ID, mNotification); } /** * Configures service as a foreground service. A foreground service is a service that's doing * something the user is actively aware of (such as playing music), and must appear to the * user as a notification. That's why we create the notification here. */ void setUpAsForeground(String text) { // mNotification = new Notification(); // mNotification.tickerText = text; // //mNotification.icon = R.drawable.ic_stat_playing; // mNotification.flags |= Notification.FLAG_ONGOING_EVENT; // startForeground(NOTIFICATION_ID, mNotification); } /** * Called when there's an error playing media. When this happens, the media player goes to * the Error state. We warn the user about the error and reset the media player. */ public boolean onError(MediaPlayer mp, int what, int extra) { Toast.makeText(getApplicationContext(), R.string.invalid_file_track, Toast.LENGTH_LONG).show(); Log.e(TAG, "Error: what=" + String.valueOf(what) + ", extra=" + String.valueOf(extra)); mState = State.Stopped; relaxResources(true); giveUpAudioFocus(); if (mPlayerEventListener != null) { mPlayerEventListener.onPlayBackError(Playback_Error.Playback_Error_Invalid_file); } return true; // true indicates we handled the error } public void onGainedAudioFocus() { //Toast.makeText(getApplicationContext(), "gained audio focus.", Toast.LENGTH_SHORT).show(); mAudioFocus = AudioFocus.Focused; // restart media player with new focus settings if (mState == State.Playing) configAndStartMediaPlayer(); } public void onLostAudioFocus(boolean canDuck) { // Toast.makeText(getApplicationContext(), "lost audio focus." + (canDuck ? "can duck" : // "no duck"), Toast.LENGTH_SHORT).show(); mAudioFocus = canDuck ? AudioFocus.NoFocusCanDuck : AudioFocus.NoFocusNoDuck; // start/restart/pause media player with new focus settings if (mPlayer != null && mPlayer.isPlaying()) configAndStartMediaPlayer(); } @Override public void onDestroy() { // Service is being killed, so make sure we release our resources mState = State.Stopped; relaxResources(true); giveUpAudioFocus(); } @Override public IBinder onBind(Intent arg0) { return musicServiceBinder; } }