1 /* ownCloud Android client application 
   2  *   Copyright (C) 2012-2013 ownCloud Inc. 
   4  *   This program is free software: you can redistribute it and/or modify 
   5  *   it under the terms of the GNU General Public License version 2, 
   6  *   as published by the Free Software Foundation. 
   8  *   This program is distributed in the hope that it will be useful, 
   9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  11  *   GNU General Public License for more details. 
  13  *   You should have received a copy of the GNU General Public License 
  14  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  18 package com
.owncloud
.android
.media
; 
  20 import android
.accounts
.Account
; 
  21 import android
.app
.Notification
; 
  22 import android
.app
.NotificationManager
; 
  23 import android
.app
.PendingIntent
; 
  24 import android
.app
.Service
; 
  25 import android
.content
.Context
; 
  26 import android
.content
.Intent
; 
  27 import android
.media
.AudioManager
; 
  28 import android
.media
.MediaPlayer
; 
  29 import android
.media
.MediaPlayer
.OnCompletionListener
; 
  30 import android
.media
.MediaPlayer
.OnErrorListener
; 
  31 import android
.media
.MediaPlayer
.OnPreparedListener
; 
  32 import android
.net
.wifi
.WifiManager
; 
  33 import android
.net
.wifi
.WifiManager
.WifiLock
; 
  34 import android
.os
.IBinder
; 
  35 import android
.os
.PowerManager
; 
  36 import android
.widget
.Toast
; 
  38 import java
.io
.IOException
; 
  40 import com
.owncloud
.android
.R
; 
  41 import com
.owncloud
.android
.datamodel
.OCFile
; 
  42 import com
.owncloud
.android
.ui
.activity
.FileActivity
; 
  43 import com
.owncloud
.android
.ui
.activity
.FileDisplayActivity
; 
  44 import com
.owncloud
.android
.utils
.Log_OC
; 
  48  * Service that handles media playback, both audio and video.  
  50  * Waits for Intents which signal the service to perform specific operations: Play, Pause, 
  53  * @author David A. Velasco 
  55 public class MediaService 
extends Service 
implements OnCompletionListener
, OnPreparedListener
, 
  56                 OnErrorListener
, AudioManager
.OnAudioFocusChangeListener 
{ 
  58     private static final String TAG 
= MediaService
.class.getSimpleName(); 
  60     private static final String MY_PACKAGE 
= MediaService
.class.getPackage() != null ? MediaService
.class.getPackage().getName() : "com.owncloud.android.media"; 
  62     /// Intent actions that we are prepared to handle 
  63     public static final String ACTION_PLAY_FILE 
= MY_PACKAGE 
+ ".action.PLAY_FILE"; 
  64     public static final String ACTION_STOP_ALL 
= MY_PACKAGE 
+ ".action.STOP_ALL"; 
  66     /// Keys to add extras to the action 
  67     public static final String EXTRA_FILE 
= MY_PACKAGE 
+ ".extra.FILE"; 
  68     public static final String EXTRA_ACCOUNT 
= MY_PACKAGE 
+ ".extra.ACCOUNT"; 
  69     public static String EXTRA_START_POSITION 
= MY_PACKAGE 
+ ".extra.START_POSITION"; 
  70     public static final String EXTRA_PLAY_ON_LOAD 
= MY_PACKAGE 
+ ".extra.PLAY_ON_LOAD"; 
  73     /** Error code for specific messages - see regular error codes at {@link MediaPlayer} */ 
  74     public static final int OC_MEDIA_ERROR 
= 0; 
  76     /** Time To keep the control panel visible when the user does not use it */ 
  77     public static final int MEDIA_CONTROL_SHORT_LIFE 
= 4000; 
  79     /** Time To keep the control panel visible when the user does not use it */ 
  80     public static final int MEDIA_CONTROL_PERMANENT 
= 0; 
  82     /** Volume to set when audio focus is lost and ducking is allowed */ 
  83     private static final float DUCK_VOLUME 
= 0.1f
; 
  85     /** Media player instance */ 
  86     private MediaPlayer mPlayer 
= null
; 
  88     /** Reference to the system AudioManager */ 
  89     private AudioManager mAudioManager 
= null
; 
  92     /** Values to indicate the state of the service */ 
 102     private State mState 
= State
.STOPPED
; 
 104     /** Possible focus values */ 
 111     /** Current focus state */ 
 112     private AudioFocus mAudioFocus 
= AudioFocus
.NO_FOCUS
; 
 115     /** 'True' when the current song is streaming from the network */ 
 116     private boolean mIsStreaming 
= false
; 
 118     /** Wifi lock kept to prevents the device from shutting off the radio when streaming a file. */ 
 119     private WifiLock mWifiLock
; 
 121     private static final String MEDIA_WIFI_LOCK_TAG 
= MY_PACKAGE 
+ ".WIFI_LOCK"; 
 123     /** Notification to keep in the notification bar while a song is playing */ 
 124     private NotificationManager mNotificationManager
; 
 125     private Notification mNotification 
= null
; 
 127     /** File being played */ 
 128     private OCFile mFile
; 
 130     /** Account holding the file being played */ 
 131     private Account mAccount
; 
 133     /** Flag signaling if the audio should be played immediately when the file is prepared */  
 134     protected boolean mPlayOnPrepared
; 
 136     /** Position, in miliseconds, where the audio should be started */ 
 137     private int mStartPosition
; 
 139     /** Interface to access the service through binding */ 
 140     private IBinder mBinder
; 
 142     /** Control panel shown to the user to control the playback, to register through binding */ 
 143     private MediaControlView mMediaController
; 
 148      * Helper method to get an error message suitable to show to users for errors occurred in media playback, 
 150      * @param context   A context to access string resources. 
 151      * @param what      See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int) 
 152      * @param extra     See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int) 
 153      * @return          Message suitable to users. 
 155     public static String 
getMessageForMediaError(Context context
, int what
, int extra
) { 
 158         if (what 
== OC_MEDIA_ERROR
) { 
 161         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_UNSUPPORTED
) { 
 162             /*  Added in API level 17 
 163                 Bitstream is conforming to the related coding standard or file spec, but the media framework does not support the feature. 
 164                 Constant Value: -1010 (0xfffffc0e) 
 166             messageId 
= R
.string
.media_err_unsupported
; 
 168         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_IO
) { 
 169             /*  Added in API level 17 
 170                 File or network related operation errors. 
 171                 Constant Value: -1004 (0xfffffc14)  
 173             messageId 
= R
.string
.media_err_io
; 
 175         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_MALFORMED
) { 
 176             /*  Added in API level 17 
 177                 Bitstream is not conforming to the related coding standard or file spec. 
 178                 Constant Value: -1007 (0xfffffc11)  
 180             messageId 
= R
.string
.media_err_malformed
; 
 182         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_TIMED_OUT
) { 
 183             /*  Added in API level 17 
 184                 Some operation takes too long to complete, usually more than 3-5 seconds. 
 185                 Constant Value: -110 (0xffffff92) 
 187             messageId 
= R
.string
.media_err_timeout
; 
 189         } else if (what 
== MediaPlayer
.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK
) { 
 190             /*  Added in API level 3 
 191                 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. 
 192                 Constant Value: 200 (0x000000c8) 
 194             messageId 
= R
.string
.media_err_invalid_progressive_playback
; 
 197             /*  MediaPlayer.MEDIA_ERROR_UNKNOWN 
 199                 Unspecified media player error. 
 200                 Constant Value: 1 (0x00000001) 
 202             /*  MediaPlayer.MEDIA_ERROR_SERVER_DIED) 
 204                 Media server died. In this case, the application must release the MediaPlayer object and instantiate a new one. 
 205                 Constant Value: 100 (0x00000064)  
 207             messageId 
= R
.string
.media_err_unknown
; 
 209         return context
.getString(messageId
); 
 215      * Initialize a service instance 
 220     public void onCreate() { 
 221         Log_OC
.d(TAG
, "Creating ownCloud media service"); 
 223         mWifiLock 
= ((WifiManager
) getSystemService(Context
.WIFI_SERVICE
)). 
 224                 createWifiLock(WifiManager
.WIFI_MODE_FULL
, MEDIA_WIFI_LOCK_TAG
); 
 226         mNotificationManager 
= (NotificationManager
) getSystemService(NOTIFICATION_SERVICE
); 
 227         mAudioManager 
= (AudioManager
) getSystemService(AUDIO_SERVICE
); 
 228         mBinder 
= new MediaServiceBinder(this); 
 233      * Entry point for Intents requesting actions, sent here via startService. 
 238     public int onStartCommand(Intent intent
, int flags
, int startId
) { 
 239         String action 
= intent
.getAction(); 
 240         if (action
.equals(ACTION_PLAY_FILE
)) {  
 241             processPlayFileRequest(intent
); 
 243         } else if (action
.equals(ACTION_STOP_ALL
)) { 
 244             processStopRequest(true
); 
 247         return START_NOT_STICKY
; // don't want it to restart in case it's killed. 
 252      * Processes a request to play a media file received as a parameter 
 254      * TODO If a new request is received when a file is being prepared, it is ignored. Is this what we want?  
 256      * @param intent    Intent received in the request with the data to identify the file to play.  
 258     private void processPlayFileRequest(Intent intent
) { 
 259         if (mState 
!= State
.PREPARING
) { 
 260             mFile 
= intent
.getExtras().getParcelable(EXTRA_FILE
); 
 261             mAccount 
= intent
.getExtras().getParcelable(EXTRA_ACCOUNT
); 
 262             mPlayOnPrepared 
= intent
.getExtras().getBoolean(EXTRA_PLAY_ON_LOAD
, false
); 
 263             mStartPosition 
= intent
.getExtras().getInt(EXTRA_START_POSITION
, 0); 
 264             tryToGetAudioFocus(); 
 271      * Processes a request to play a media file. 
 273     protected void processPlayRequest() { 
 274         // request audio focus 
 275         tryToGetAudioFocus(); 
 277         // actually play the song 
 278         if (mState 
== State
.STOPPED
) { 
 279             // (re)start playback 
 282         } else if (mState 
== State
.PAUSED
) { 
 284             mState 
= State
.PLAYING
; 
 285             setUpAsForeground(String
.format(getString(R
.string
.media_state_playing
), mFile
.getFileName())); 
 286             configAndStartMediaPlayer(); 
 293      * Makes sure the media player exists and has been reset. This will create the media player 
 294      * if needed. reset the existing media player if one already exists. 
 296     protected void createMediaPlayerIfNeeded() { 
 297         if (mPlayer 
== null
) { 
 298             mPlayer 
= new MediaPlayer(); 
 300             // make sure the CPU won't go to sleep while media is playing 
 301             mPlayer
.setWakeMode(getApplicationContext(), PowerManager
.PARTIAL_WAKE_LOCK
); 
 303             // the media player will notify the service when it's ready preparing, and when it's done playing 
 304             mPlayer
.setOnPreparedListener(this); 
 305             mPlayer
.setOnCompletionListener(this); 
 306             mPlayer
.setOnErrorListener(this); 
 314      * Processes a request to pause the current playback  
 316     protected void processPauseRequest() { 
 317         if (mState 
== State
.PLAYING
) { 
 318             mState 
= State
.PAUSED
; 
 320             releaseResources(false
); // retain media player in pause 
 321             // TODO polite audio focus, instead of keep it owned; or not? 
 327      * Processes a request to stop the playback. 
 329      * @param   force       When 'true', the playback is stopped no matter the value of mState 
 331     protected void processStopRequest(boolean force
) { 
 332         if (mState 
!= State
.PREPARING 
|| force
) { 
 333             mState 
= State
.STOPPED
; 
 336             releaseResources(true
); 
 338             stopSelf();     // service is no longer necessary 
 344      * Releases resources used by the service for playback. This includes the "foreground service" 
 345      * status and notification, the wake locks and possibly the MediaPlayer. 
 347      * @param releaseMediaPlayer    Indicates whether the Media Player should also be released or not 
 349     protected void releaseResources(boolean releaseMediaPlayer
) { 
 350         // stop being a foreground service 
 351         stopForeground(true
); 
 353         // stop and release the Media Player, if it's available 
 354         if (releaseMediaPlayer 
&& mPlayer 
!= null
) { 
 360         // release the Wifi lock, if holding it 
 361         if (mWifiLock
.isHeld()) { 
 368      * Fully releases the audio focus. 
 370     private void giveUpAudioFocus() { 
 371         if (mAudioFocus 
== AudioFocus
.FOCUS 
 
 372                 && mAudioManager 
!= null  
 
 373                 && AudioManager
.AUDIOFOCUS_REQUEST_GRANTED 
== mAudioManager
.abandonAudioFocus(this))  { 
 375             mAudioFocus 
= AudioFocus
.NO_FOCUS
; 
 381      * Reconfigures MediaPlayer according to audio focus settings and starts/restarts it.  
 383     protected void configAndStartMediaPlayer() { 
 384         if (mPlayer 
== null
) { 
 385             throw new IllegalStateException("mPlayer is NULL"); 
 388         if (mAudioFocus 
== AudioFocus
.NO_FOCUS
) { 
 389             if (mPlayer
.isPlaying()) { 
 390                 mPlayer
.pause();        // have to be polite; but mState is not changed, to resume when focus is received again 
 394             if (mAudioFocus 
== AudioFocus
.NO_FOCUS_CAN_DUCK
) { 
 395                 mPlayer
.setVolume(DUCK_VOLUME
, DUCK_VOLUME
); 
 398                 mPlayer
.setVolume(1.0f
, 1.0f
); // full volume 
 401             if (!mPlayer
.isPlaying()) { 
 409      * Requests the audio focus to the Audio Manager  
 411     private void tryToGetAudioFocus() { 
 412         if (mAudioFocus 
!= AudioFocus
.FOCUS 
 
 413                 && mAudioManager 
!= null 
 
 414                 && (AudioManager
.AUDIOFOCUS_REQUEST_GRANTED 
== mAudioManager
.requestAudioFocus( this, 
 415                                                                                                 AudioManager
.STREAM_MUSIC
,  
 416                                                                                                 AudioManager
.AUDIOFOCUS_GAIN
)) 
 418             mAudioFocus 
= AudioFocus
.FOCUS
; 
 424      * Starts playing the current media file.  
 426     protected void playMedia() { 
 427         mState 
= State
.STOPPED
; 
 428         releaseResources(false
); // release everything except MediaPlayer 
 432                 Toast
.makeText(this, R
.string
.media_err_nothing_to_play
, Toast
.LENGTH_LONG
).show(); 
 433                 processStopRequest(true
); 
 436             } else if (mAccount 
== null
) { 
 437                 Toast
.makeText(this, R
.string
.media_err_not_in_owncloud
, Toast
.LENGTH_LONG
).show(); 
 438                 processStopRequest(true
); 
 442             createMediaPlayerIfNeeded(); 
 443             mPlayer
.setAudioStreamType(AudioManager
.STREAM_MUSIC
); 
 444             String url 
= mFile
.getStoragePath(); 
 445             /* Streaming is not possible right now 
 446             if (url == null || url.length() <= 0) { 
 447                 url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath(); 
 449             mIsStreaming = url.startsWith("http:") || url.startsWith("https:"); 
 451             mIsStreaming 
= false
; 
 453             mPlayer
.setDataSource(url
); 
 455             mState 
= State
.PREPARING
; 
 456             setUpAsForeground(String
.format(getString(R
.string
.media_state_loading
), mFile
.getFileName())); 
 458             // starts preparing the media player in background 
 459             mPlayer
.prepareAsync(); 
 461             // prevent the Wifi from going to sleep when streaming 
 464             } else if (mWifiLock
.isHeld()) { 
 468         } catch (SecurityException e
) { 
 469             Log_OC
.e(TAG
, "SecurityException playing " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 470             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_security_ex
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 471             processStopRequest(true
); 
 473         } catch (IOException e
) { 
 474             Log_OC
.e(TAG
, "IOException playing " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 475             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_io_ex
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 476             processStopRequest(true
); 
 478         } catch (IllegalStateException e
) { 
 479             Log_OC
.e(TAG
, "IllegalStateException " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 480             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_unexpected
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 481             processStopRequest(true
); 
 483         } catch (IllegalArgumentException e
) { 
 484             Log_OC
.e(TAG
, "IllegalArgumentException " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 485             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_unexpected
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 486             processStopRequest(true
); 
 491     /** Called when media player is done playing current song. */ 
 492     public void onCompletion(MediaPlayer player
) { 
 493         Toast
.makeText(this, String
.format(getString(R
.string
.media_event_done
, mFile
.getFileName())), Toast
.LENGTH_LONG
).show(); 
 494         if (mMediaController 
!= null
) { 
 495             // somebody is still bound to the service 
 497             processPauseRequest(); 
 498             mMediaController
.updatePausePlay(); 
 501             processStopRequest(true
); 
 508      * Called when media player is done preparing.  
 512     public void onPrepared(MediaPlayer player
) { 
 513         mState 
= State
.PLAYING
; 
 514         updateNotification(String
.format(getString(R
.string
.media_state_playing
), mFile
.getFileName())); 
 515         if (mMediaController 
!= null
) { 
 516             mMediaController
.setEnabled(true
); 
 518         player
.seekTo(mStartPosition
); 
 519         configAndStartMediaPlayer(); 
 520         if (!mPlayOnPrepared
) { 
 521             processPauseRequest(); 
 524         if (mMediaController 
!= null
) { 
 525             mMediaController
.updatePausePlay(); 
 531      * Updates the status notification 
 533     @SuppressWarnings("deprecation") 
 534     private void updateNotification(String content
) { 
 535         // TODO check if updating the Intent is really necessary 
 536         Intent showDetailsIntent 
= new Intent(this, FileDisplayActivity
.class); 
 537         showDetailsIntent
.putExtra(FileActivity
.EXTRA_FILE
, mFile
); 
 538         showDetailsIntent
.putExtra(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 539         showDetailsIntent
.setFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
); 
 540         mNotification
.contentIntent 
= PendingIntent
.getActivity(getApplicationContext(),  
 541                                                                 (int)System
.currentTimeMillis(),  
 543                                                                 PendingIntent
.FLAG_UPDATE_CURRENT
); 
 544         mNotification
.when 
= System
.currentTimeMillis(); 
 545         //mNotification.contentView.setTextViewText(R.id.status_text, content); 
 546         String ticker 
= String
.format(getString(R
.string
.media_notif_ticker
), getString(R
.string
.app_name
)); 
 547         mNotification
.setLatestEventInfo(getApplicationContext(), ticker
, content
, mNotification
.contentIntent
); 
 548         mNotificationManager
.notify(R
.string
.media_notif_ticker
, mNotification
); 
 553      * Configures the service as a foreground service. 
 555      * The system will avoid finishing the service as much as possible when resources as low. 
 557      * A notification must be created to keep the user aware of the existance of the service. 
 559     @SuppressWarnings("deprecation") 
 560     private void setUpAsForeground(String content
) { 
 561         /// creates status notification 
 562         // TODO put a progress bar to follow the playback progress 
 563         mNotification 
= new Notification(); 
 564         mNotification
.icon 
= android
.R
.drawable
.ic_media_play
; 
 565         //mNotification.tickerText = text; 
 566         mNotification
.when 
= System
.currentTimeMillis(); 
 567         mNotification
.flags 
|= Notification
.FLAG_ONGOING_EVENT
; 
 568         //mNotification.contentView.setTextViewText(R.id.status_text, "ownCloud Music Player");     // NULL POINTER 
 569         //mNotification.contentView.setTextViewText(R.id.status_text, getString(R.string.downloader_download_in_progress_content)); 
 572         /// includes a pending intent in the notification showing the details view of the file 
 573         Intent showDetailsIntent 
= new Intent(this, FileDisplayActivity
.class); 
 574         showDetailsIntent
.putExtra(FileActivity
.EXTRA_FILE
, mFile
); 
 575         showDetailsIntent
.putExtra(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 576         showDetailsIntent
.setFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
); 
 577         mNotification
.contentIntent 
= PendingIntent
.getActivity(getApplicationContext(),  
 578                                                                 (int)System
.currentTimeMillis(),  
 580                                                                 PendingIntent
.FLAG_UPDATE_CURRENT
); 
 583         //mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); 
 584         String ticker 
= String
.format(getString(R
.string
.media_notif_ticker
), getString(R
.string
.app_name
)); 
 585         mNotification
.setLatestEventInfo(getApplicationContext(), ticker
, content
, mNotification
.contentIntent
); 
 586         startForeground(R
.string
.media_notif_ticker
, mNotification
); 
 591      * Called when there's an error playing media.  
 593      * Warns the user about the error and resets the media player. 
 595     public boolean onError(MediaPlayer mp
, int what
, int extra
) { 
 596         Log_OC
.e(TAG
, "Error in audio playback, what = " + what 
+ ", extra = " + extra
); 
 598         String message 
= getMessageForMediaError(this, what
, extra
); 
 599         Toast
.makeText(getApplicationContext(), message
, Toast
.LENGTH_SHORT
).show(); 
 601         processStopRequest(true
); 
 606      * Called by the system when another app tries to play some sound. 
 611     public void onAudioFocusChange(int focusChange
) { 
 612         if (focusChange 
> 0) { 
 613             // focus gain; check AudioManager.AUDIOFOCUS_* values 
 614             mAudioFocus 
= AudioFocus
.FOCUS
; 
 615             // restart media player with new focus settings 
 616             if (mState 
== State
.PLAYING
) 
 617                 configAndStartMediaPlayer(); 
 619         } else if (focusChange 
< 0) { 
 620             // focus loss; check AudioManager.AUDIOFOCUS_* values 
 621             boolean canDuck 
= AudioManager
.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 
== focusChange
; 
 622                 mAudioFocus 
= canDuck ? AudioFocus
.NO_FOCUS_CAN_DUCK 
: AudioFocus
.NO_FOCUS
; 
 623                 // start/restart/pause media player with new focus settings 
 624                 if (mPlayer 
!= null 
&& mPlayer
.isPlaying()) 
 625                     configAndStartMediaPlayer(); 
 631      * Called when the service is finished for final clean-up. 
 636     public void onDestroy() { 
 637         mState 
= State
.STOPPED
; 
 638         releaseResources(true
); 
 644      * Provides a binder object that clients can use to perform operations on the MediaPlayer managed by the MediaService.  
 647     public IBinder 
onBind(Intent arg
) { 
 653      * Called when ALL the bound clients were onbound. 
 655      * The service is destroyed if playback stopped or paused 
 658     public boolean onUnbind(Intent intent
) { 
 659         if (mState 
== State
.PAUSED 
|| mState 
== State
.STOPPED
)  { 
 660             processStopRequest(false
); 
 662         return false
;   // not accepting rebinding (default behaviour) 
 667      * Accesses the current MediaPlayer instance in the service. 
 669      * To be handled carefully. Visibility is protected to be accessed only  
 671      * @return Current MediaPlayer instance handled by MediaService. 
 673     protected MediaPlayer 
getPlayer() { 
 679      * Accesses the current OCFile loaded in the service. 
 681      * @return  The current OCFile loaded in the service. 
 683     protected OCFile 
getCurrentFile() { 
 689      * Accesses the current {@link State} of the MediaService. 
 691      * @return  The current {@link State} of the MediaService. 
 693     protected State 
getState() { 
 698     protected void setMediaContoller(MediaControlView mediaController
) { 
 699         mMediaController 
= mediaController
; 
 702     protected MediaControlView 
getMediaController() { 
 703         return mMediaController
;