X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/7018ae7e1f3989779bf47b86e762b7521b7df20e..901b6ac61e4a84d281e86b4989aa099801b28de7:/src/com/owncloud/android/media/MediaService.java?ds=inline diff --git a/src/com/owncloud/android/media/MediaService.java b/src/com/owncloud/android/media/MediaService.java index 8020f121..0a746355 100644 --- a/src/com/owncloud/android/media/MediaService.java +++ b/src/com/owncloud/android/media/MediaService.java @@ -1,10 +1,9 @@ /* ownCloud Android client application - * Copyright 2013 ownCloud Inc. + * Copyright (C) 2012-2013 ownCloud Inc. * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,7 +22,6 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; -import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.media.AudioManager; @@ -31,23 +29,20 @@ import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; -import android.net.Uri; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.os.IBinder; import android.os.PowerManager; -import android.util.Log; -import android.widget.RemoteViews; import android.widget.Toast; -import java.io.File; import java.io.IOException; -import com.owncloud.android.AccountUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.ui.activity.FileDetailActivity; -import com.owncloud.android.ui.fragment.FileDetailFragment; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.utils.Log_OC; + /** * Service that handles media playback, both audio and video. @@ -65,40 +60,36 @@ public class MediaService extends Service implements OnCompletionListener, OnPre private static final String MY_PACKAGE = MediaService.class.getPackage() != null ? MediaService.class.getPackage().getName() : "com.owncloud.android.media"; /// Intent actions that we are prepared to handle - public static final String ACTION_TOGGLE_PLAYBACK = MY_PACKAGE + ".action.TOGGLE_PLAYBACK"; - public static final String ACTION_PLAY = MY_PACKAGE + ".action.PLAY"; - public static final String ACTION_PAUSE = MY_PACKAGE + ".android.media.action.PAUSE"; - public static final String ACTION_STOP = MY_PACKAGE + ".android.media.action.STOP"; - public static final String ACTION_REWIND = MY_PACKAGE + ".android.media.action.REWIND"; - public static final String ACTION_PLAY_FILE = MY_PACKAGE + ".android.media.action.URL"; + public static final String ACTION_PLAY_FILE = MY_PACKAGE + ".action.PLAY_FILE"; + public static final String ACTION_STOP_ALL = MY_PACKAGE + ".action.STOP_ALL"; /// Keys to add extras to the action public static final String EXTRA_FILE = MY_PACKAGE + ".extra.FILE"; public static final String EXTRA_ACCOUNT = MY_PACKAGE + ".extra.ACCOUNT"; + public static String EXTRA_START_POSITION = MY_PACKAGE + ".extra.START_POSITION"; + public static final String EXTRA_PLAY_ON_LOAD = MY_PACKAGE + ".extra.PLAY_ON_LOAD"; + + + /** Error code for specific messages - see regular error codes at {@link MediaPlayer} */ + public static final int OC_MEDIA_ERROR = 0; + + /** Time To keep the control panel visible when the user does not use it */ + public static final int MEDIA_CONTROL_SHORT_LIFE = 4000; - /** - * Volume to set when audio focus is lost and ducking is allowed - */ + /** Time To keep the control panel visible when the user does not use it */ + public static final int MEDIA_CONTROL_PERMANENT = 0; + + /** Volume to set when audio focus is lost and ducking is allowed */ private static final float DUCK_VOLUME = 0.1f; - /** - * Media player instance - */ + /** Media player instance */ private 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; - /** - * Reference to the system AudioManager - */ + /** Reference to the system AudioManager */ private AudioManager mAudioManager = null; - /** - * Values to indicate the state of the service - */ + /** Values to indicate the state of the service */ enum State { STOPPED, PREPARING, @@ -107,58 +98,119 @@ public class MediaService extends Service implements OnCompletionListener, OnPre }; - /** - * Current state - */ + /** Current state */ private State mState = State.STOPPED; - - enum PauseReason { - UserRequest, // paused by user request - FocusLoss, // paused because of audio focus loss - }; - - - /** - * Possible focus values - */ + /** Possible focus values */ enum AudioFocus { NO_FOCUS, NO_FOCUS_CAN_DUCK, FOCUS } - /** - * Current focus state - */ + /** Current focus state */ private AudioFocus mAudioFocus = AudioFocus.NO_FOCUS; - /** - * 'True' when the current song is streaming from the network - */ + /** 'True' when the current song is streaming from the network */ private boolean mIsStreaming = false; - /** - * Wifi lock kept to prevents the device from shutting off the radio when streaming a file. - */ + /** Wifi lock kept to prevents the device from shutting off the radio when streaming a file. */ private WifiLock mWifiLock; + private static final String MEDIA_WIFI_LOCK_TAG = MY_PACKAGE + ".WIFI_LOCK"; - - - /** - * Id for the notification to keep in the notification bar while a song is playing - */ - private final int NOTIFICATION_ID = 1; + /** Notification to keep in the notification bar while a song is playing */ private NotificationManager mNotificationManager; private Notification mNotification = null; - + + /** File being played */ private OCFile mFile; + + /** Account holding the file being played */ private Account mAccount; + + /** Flag signaling if the audio should be played immediately when the file is prepared */ + protected boolean mPlayOnPrepared; + + /** Position, in miliseconds, where the audio should be started */ + private int mStartPosition; + /** Interface to access the service through binding */ + private IBinder mBinder; + + /** Control panel shown to the user to control the playback, to register through binding */ + private MediaControlView mMediaController; + + /** + * Helper method to get an error message suitable to show to users for errors occurred in media playback, + * + * @param context A context to access string resources. + * @param what See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int) + * @param extra See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int) + * @return Message suitable to users. + */ + public static String getMessageForMediaError(Context context, int what, int extra) { + int messageId; + + if (what == OC_MEDIA_ERROR) { + messageId = extra; + + } else if (extra == MediaPlayer.MEDIA_ERROR_UNSUPPORTED) { + /* Added in API level 17 + Bitstream is conforming to the related coding standard or file spec, but the media framework does not support the feature. + Constant Value: -1010 (0xfffffc0e) + */ + messageId = R.string.media_err_unsupported; + + } else if (extra == MediaPlayer.MEDIA_ERROR_IO) { + /* Added in API level 17 + File or network related operation errors. + Constant Value: -1004 (0xfffffc14) + */ + messageId = R.string.media_err_io; + + } else if (extra == MediaPlayer.MEDIA_ERROR_MALFORMED) { + /* Added in API level 17 + Bitstream is not conforming to the related coding standard or file spec. + Constant Value: -1007 (0xfffffc11) + */ + messageId = R.string.media_err_malformed; + + } else if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) { + /* Added in API level 17 + Some operation takes too long to complete, usually more than 3-5 seconds. + Constant Value: -110 (0xffffff92) + */ + messageId = R.string.media_err_timeout; + + } else if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { + /* Added in API level 3 + The video is streamed and its container is not valid for progressive playback i.e the video's index (e.g moov atom) is not at the start of the file. + Constant Value: 200 (0x000000c8) + */ + messageId = R.string.media_err_invalid_progressive_playback; + + } else { + /* MediaPlayer.MEDIA_ERROR_UNKNOWN + Added in API level 1 + Unspecified media player error. + Constant Value: 1 (0x00000001) + */ + /* MediaPlayer.MEDIA_ERROR_SERVER_DIED) + Added in API level 1 + Media server died. In this case, the application must release the MediaPlayer object and instantiate a new one. + Constant Value: 100 (0x00000064) + */ + messageId = R.string.media_err_unknown; + } + return context.getString(messageId); + } + + + /** * Initialize a service instance * @@ -166,37 +218,30 @@ public class MediaService extends Service implements OnCompletionListener, OnPre */ @Override public void onCreate() { - Log.d(TAG, "Creating ownCloud media service"); + Log_OC.d(TAG, "Creating ownCloud media service"); mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)). createWifiLock(WifiManager.WIFI_MODE_FULL, MEDIA_WIFI_LOCK_TAG); mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); - + mBinder = new MediaServiceBinder(this); } /** * Entry point for Intents requesting actions, sent here via startService. * - * TODO maybe, replace by an API based in binding + * {@inheritDoc} */ @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if (action.equals(ACTION_PLAY_FILE)) { processPlayFileRequest(intent); - } else if (action.equals(ACTION_PLAY)) { - processPlayRequest(); - } else if (action.equals(ACTION_TOGGLE_PLAYBACK)) { - processTogglePlaybackRequest(); - } else if (action.equals(ACTION_PAUSE)) { - processPauseRequest(); - } else if (action.equals(ACTION_STOP)) { - processStopRequest(); - } else if (action.equals(ACTION_REWIND)) { - processRewindRequest(); + + } else if (action.equals(ACTION_STOP_ALL)) { + processStopRequest(true); } return START_NOT_STICKY; // don't want it to restart in case it's killed. @@ -206,23 +251,26 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /** * Processes a request to play a media file received as a parameter * + * TODO If a new request is received when a file is being prepared, it is ignored. Is this what we want? + * * @param intent Intent received in the request with the data to identify the file to play. */ private void processPlayFileRequest(Intent intent) { - if (mState == State.PLAYING || mState == State.PAUSED || mState == State.STOPPED) { + if (mState != State.PREPARING) { mFile = intent.getExtras().getParcelable(EXTRA_FILE); mAccount = intent.getExtras().getParcelable(EXTRA_ACCOUNT); + mPlayOnPrepared = intent.getExtras().getBoolean(EXTRA_PLAY_ON_LOAD, false); + mStartPosition = intent.getExtras().getInt(EXTRA_START_POSITION, 0); tryToGetAudioFocus(); playMedia(); } - // TODO think what happens if mState == State.PREPARING } /** * Processes a request to play a media file. */ - void processPlayRequest() { + protected void processPlayRequest() { // request audio focus tryToGetAudioFocus(); @@ -243,9 +291,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /** * 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. + * if needed. reset the existing media player if one already exists. */ - void createMediaPlayerIfNeeded() { + protected void createMediaPlayerIfNeeded() { if (mPlayer == null) { mPlayer = new MediaPlayer(); @@ -263,21 +311,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre } /** - * Processes a request to toggle from PLAY to PAUSE, or from PAUSE to PLAY - */ - private void processTogglePlaybackRequest() { - if (mState == State.PAUSED || mState == State.STOPPED) { - processPlayRequest(); - - } else { - processPauseRequest(); - } - } - - /** * Processes a request to pause the current playback */ - private void processPauseRequest() { + protected void processPauseRequest() { if (mState == State.PLAYING) { mState = State.PAUSED; mPlayer.pause(); @@ -288,31 +324,15 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /** - * Process a request to rewind the current media playback to the start point. - */ - private void processRewindRequest() { - if (mState == State.PLAYING || mState == State.PAUSED) { - mPlayer.seekTo(0); - } - } - - /** - * Processes a request to stop the playback - */ - private void processStopRequest() { - processStopRequest(false); - } - - - /** * Processes a request to stop the playback. * * @param force When 'true', the playback is stopped no matter the value of mState */ - void processStopRequest(boolean force) { - if (mState == State.PLAYING || mState == State.PAUSED || force) { + protected void processStopRequest(boolean force) { + if (mState != State.PREPARING || force) { mState = State.STOPPED; - + mFile = null; + mAccount = null; releaseResources(true); giveUpAudioFocus(); stopSelf(); // service is no longer necessary @@ -326,7 +346,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre * * @param releaseMediaPlayer Indicates whether the Media Player should also be released or not */ - void releaseResources(boolean releaseMediaPlayer) { + protected void releaseResources(boolean releaseMediaPlayer) { // stop being a foreground service stopForeground(true); @@ -360,7 +380,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /** * Reconfigures MediaPlayer according to audio focus settings and starts/restarts it. */ - void configAndStartMediaPlayer() { + protected void configAndStartMediaPlayer() { if (mPlayer == null) { throw new IllegalStateException("mPlayer is NULL"); } @@ -400,53 +420,10 @@ public class MediaService extends Service implements OnCompletionListener, OnPre } - public static class Item { - long id; - String artist; - String title; - String album; - long duration; - - public Item(long id, String artist, String title, String album, long duration) { - this.id = id; - this.artist = artist; - this.title = title; - this.album = album; - this.duration = duration; - } - - public long getId() { - return id; - } - - public String getArtist() { - return artist; - } - - public String getTitle() { - return title; - } - - public String getAlbum() { - return album; - } - - public long getDuration() { - return duration; - } - - public Uri getURI() { - return ContentUris.withAppendedId( - android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id); - } - } - - - /** * Starts playing the current media file. */ - void playMedia() { + protected void playMedia() { mState = State.STOPPED; releaseResources(false); // release everything except MediaPlayer @@ -465,10 +442,13 @@ public class MediaService extends Service implements OnCompletionListener, OnPre createMediaPlayerIfNeeded(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); String url = mFile.getStoragePath(); + /* Streaming is not possible right now if (url == null || url.length() <= 0) { url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath(); } mIsStreaming = url.startsWith("http:") || url.startsWith("https:"); + */ + mIsStreaming = false; mPlayer.setDataSource(url); @@ -486,19 +466,24 @@ public class MediaService extends Service implements OnCompletionListener, OnPre } } catch (SecurityException e) { - Log.e(TAG, "SecurityException playing " + mAccount.name + mFile.getRemotePath(), e); - // TODO message to the user + Log_OC.e(TAG, "SecurityException playing " + mAccount.name + mFile.getRemotePath(), e); + Toast.makeText(this, String.format(getString(R.string.media_err_security_ex), mFile.getFileName()), Toast.LENGTH_LONG).show(); + processStopRequest(true); } catch (IOException e) { - Log.e(TAG, "IOException playing " + mAccount.name + mFile.getRemotePath(), e); - // TODO message to the user + Log_OC.e(TAG, "IOException playing " + mAccount.name + mFile.getRemotePath(), e); + Toast.makeText(this, String.format(getString(R.string.media_err_io_ex), mFile.getFileName()), Toast.LENGTH_LONG).show(); + processStopRequest(true); } catch (IllegalStateException e) { - Log.e(TAG, "IllegalStateException " + mAccount.name + mFile.getRemotePath(), e); + Log_OC.e(TAG, "IllegalStateException " + mAccount.name + mFile.getRemotePath(), e); + Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show(); + processStopRequest(true); } catch (IllegalArgumentException e) { - Log.e(TAG, "IllegalArgumentException " + mAccount.name + mFile.getRemotePath(), e); - e.printStackTrace(); + Log_OC.e(TAG, "IllegalArgumentException " + mAccount.name + mFile.getRemotePath(), e); + Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show(); + processStopRequest(true); } } @@ -506,7 +491,15 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /** Called when media player is done playing current song. */ public void onCompletion(MediaPlayer player) { Toast.makeText(this, String.format(getString(R.string.media_event_done, mFile.getFileName())), Toast.LENGTH_LONG).show(); - processStopRequest(true); + if (mMediaController != null) { + // somebody is still bound to the service + player.seekTo(0); + processPauseRequest(); + mMediaController.updatePausePlay(); + } else { + // nobody is bound + processStopRequest(true); + } return; } @@ -519,7 +512,18 @@ public class MediaService extends Service implements OnCompletionListener, OnPre public void onPrepared(MediaPlayer player) { mState = State.PLAYING; updateNotification(String.format(getString(R.string.media_state_playing), mFile.getFileName())); + if (mMediaController != null) { + mMediaController.setEnabled(true); + } + player.seekTo(mStartPosition); configAndStartMediaPlayer(); + if (!mPlayOnPrepared) { + processPauseRequest(); + } + + if (mMediaController != null) { + mMediaController.updatePausePlay(); + } } @@ -529,9 +533,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre @SuppressWarnings("deprecation") private void updateNotification(String content) { // TODO check if updating the Intent is really necessary - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, mFile); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount); + Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class); + showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, mFile); + showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), @@ -539,9 +543,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre PendingIntent.FLAG_UPDATE_CURRENT); mNotification.when = System.currentTimeMillis(); //mNotification.contentView.setTextViewText(R.id.status_text, content); - String ticker = "ownCloud MusicPlayer"; + String ticker = String.format(getString(R.string.media_notif_ticker), getString(R.string.app_name)); mNotification.setLatestEventInfo(getApplicationContext(), ticker, content, mNotification.contentIntent); - mNotificationManager.notify(NOTIFICATION_ID, mNotification); + mNotificationManager.notify(R.string.media_notif_ticker, mNotification); } @@ -566,9 +570,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /// includes a pending intent in the notification showing the details view of the file - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, mFile); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount); + Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class); + showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, mFile); + showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), @@ -577,9 +581,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre //mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); - String ticker = "ownCloud MusicPlayer"; + String ticker = String.format(getString(R.string.media_notif_ticker), getString(R.string.app_name)); mNotification.setLatestEventInfo(getApplicationContext(), ticker, content, mNotification.contentIntent); - startForeground(NOTIFICATION_ID, mNotification); + startForeground(R.string.media_notif_ticker, mNotification); } @@ -589,19 +593,15 @@ public class MediaService extends Service implements OnCompletionListener, OnPre * Warns the user about the error and resets the media player. */ public boolean onError(MediaPlayer mp, int what, int extra) { - // TODO FOLLOW HERE!!!!!! + Log_OC.e(TAG, "Error in audio playback, what = " + what + ", extra = " + extra); - Toast.makeText(getApplicationContext(), "Media player error! Resetting.", - Toast.LENGTH_SHORT).show(); - Log.e(TAG, "Error: what=" + String.valueOf(what) + ", extra=" + String.valueOf(extra)); - - mState = State.STOPPED; - releaseResources(true); - giveUpAudioFocus(); + String message = getMessageForMediaError(this, what, extra); + Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); + + processStopRequest(true); return true; } - /** * Called by the system when another app tries to play some sound. * @@ -611,9 +611,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre public void onAudioFocusChange(int focusChange) { if (focusChange > 0) { // focus gain; check AudioManager.AUDIOFOCUS_* values - Toast.makeText(getApplicationContext(), "gained audio focus.", Toast.LENGTH_SHORT).show(); mAudioFocus = AudioFocus.FOCUS; - // restart media player with new focus settings if (mState == State.PLAYING) configAndStartMediaPlayer(); @@ -621,10 +619,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre } else if (focusChange < 0) { // focus loss; check AudioManager.AUDIOFOCUS_* values boolean canDuck = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK == focusChange; - Toast.makeText(getApplicationContext(), "lost audio focus." + (canDuck ? "can duck" : - "no duck"), Toast.LENGTH_SHORT).show(); mAudioFocus = canDuck ? AudioFocus.NO_FOCUS_CAN_DUCK : AudioFocus.NO_FOCUS; - // start/restart/pause media player with new focus settings if (mPlayer != null && mPlayer.isPlaying()) configAndStartMediaPlayer(); @@ -645,10 +640,67 @@ public class MediaService extends Service implements OnCompletionListener, OnPre } + /** + * Provides a binder object that clients can use to perform operations on the MediaPlayer managed by the MediaService. + */ @Override - public IBinder onBind(Intent arg0) { - // TODO provide a binding API? may we use a service to play VIDEO? - return null; + public IBinder onBind(Intent arg) { + return mBinder; + } + + + /** + * Called when ALL the bound clients were onbound. + * + * The service is destroyed if playback stopped or paused + */ + @Override + public boolean onUnbind(Intent intent) { + if (mState == State.PAUSED || mState == State.STOPPED) { + processStopRequest(false); + } + return false; // not accepting rebinding (default behaviour) + } + + + /** + * Accesses the current MediaPlayer instance in the service. + * + * To be handled carefully. Visibility is protected to be accessed only + * + * @return Current MediaPlayer instance handled by MediaService. + */ + protected MediaPlayer getPlayer() { + return mPlayer; + } + + + /** + * Accesses the current OCFile loaded in the service. + * + * @return The current OCFile loaded in the service. + */ + protected OCFile getCurrentFile() { + return mFile; + } + + + /** + * Accesses the current {@link State} of the MediaService. + * + * @return The current {@link State} of the MediaService. + */ + protected State getState() { + return mState; + } + + + protected void setMediaContoller(MediaControlView mediaController) { + mMediaController = mediaController; + } + + protected MediaControlView getMediaController() { + return mMediaController; } }