2  *   ownCloud Android client application 
   4  *   @author David A. Velasco 
   5  *   Copyright (C) 2015 ownCloud Inc. 
   7  *   This program is free software: you can redistribute it and/or modify 
   8  *   it under the terms of the GNU General Public License version 2, 
   9  *   as published by the Free Software Foundation. 
  11  *   This program is distributed in the hope that it will be useful, 
  12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  14  *   GNU General Public License for more details. 
  16  *   You should have received a copy of the GNU General Public License 
  17  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  21 package com
.owncloud
.android
.media
; 
  23 import android
.accounts
.Account
; 
  24 import android
.app
.Notification
; 
  25 import android
.app
.NotificationManager
; 
  26 import android
.app
.PendingIntent
; 
  27 import android
.app
.Service
; 
  28 import android
.content
.Context
; 
  29 import android
.content
.Intent
; 
  30 import android
.media
.AudioManager
; 
  31 import android
.media
.MediaPlayer
; 
  32 import android
.media
.MediaPlayer
.OnCompletionListener
; 
  33 import android
.media
.MediaPlayer
.OnErrorListener
; 
  34 import android
.media
.MediaPlayer
.OnPreparedListener
; 
  35 import android
.net
.wifi
.WifiManager
; 
  36 import android
.net
.wifi
.WifiManager
.WifiLock
; 
  37 import android
.os
.IBinder
; 
  38 import android
.os
.PowerManager
; 
  39 import android
.widget
.Toast
; 
  41 import java
.io
.IOException
; 
  43 import com
.owncloud
.android
.R
; 
  44 import com
.owncloud
.android
.datamodel
.OCFile
; 
  45 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
; 
  46 import com
.owncloud
.android
.ui
.activity
.FileActivity
; 
  47 import com
.owncloud
.android
.ui
.activity
.FileDisplayActivity
; 
  51  * Service that handles media playback, both audio and video.  
  53  * Waits for Intents which signal the service to perform specific operations: Play, Pause, 
  56 public class MediaService 
extends Service 
implements OnCompletionListener
, OnPreparedListener
, 
  57                 OnErrorListener
, AudioManager
.OnAudioFocusChangeListener 
{ 
  59     private static final String TAG 
= MediaService
.class.getSimpleName(); 
  61     private static final String MY_PACKAGE 
= MediaService
.class.getPackage() != null ? MediaService
.class.getPackage().getName() : "com.owncloud.android.media"; 
  63     /// Intent actions that we are prepared to handle 
  64     public static final String ACTION_PLAY_FILE 
= MY_PACKAGE 
+ ".action.PLAY_FILE"; 
  65     public static final String ACTION_STOP_ALL 
= MY_PACKAGE 
+ ".action.STOP_ALL"; 
  67     /// Keys to add extras to the action 
  68     public static final String EXTRA_FILE 
= MY_PACKAGE 
+ ".extra.FILE"; 
  69     public static final String EXTRA_ACCOUNT 
= MY_PACKAGE 
+ ".extra.ACCOUNT"; 
  70     public static String EXTRA_START_POSITION 
= MY_PACKAGE 
+ ".extra.START_POSITION"; 
  71     public static final String EXTRA_PLAY_ON_LOAD 
= MY_PACKAGE 
+ ".extra.PLAY_ON_LOAD"; 
  74     /** Error code for specific messages - see regular error codes at {@link MediaPlayer} */ 
  75     public static final int OC_MEDIA_ERROR 
= 0; 
  77     /** Time To keep the control panel visible when the user does not use it */ 
  78     public static final int MEDIA_CONTROL_SHORT_LIFE 
= 4000; 
  80     /** Time To keep the control panel visible when the user does not use it */ 
  81     public static final int MEDIA_CONTROL_PERMANENT 
= 0; 
  83     /** Volume to set when audio focus is lost and ducking is allowed */ 
  84     private static final float DUCK_VOLUME 
= 0.1f
; 
  86     /** Media player instance */ 
  87     private MediaPlayer mPlayer 
= null
; 
  89     /** Reference to the system AudioManager */ 
  90     private AudioManager mAudioManager 
= null
; 
  93     /** Values to indicate the state of the service */ 
 103     private State mState 
= State
.STOPPED
; 
 105     /** Possible focus values */ 
 112     /** Current focus state */ 
 113     private AudioFocus mAudioFocus 
= AudioFocus
.NO_FOCUS
; 
 116     /** 'True' when the current song is streaming from the network */ 
 117     private boolean mIsStreaming 
= false
; 
 119     /** Wifi lock kept to prevents the device from shutting off the radio when streaming a file. */ 
 120     private WifiLock mWifiLock
; 
 122     private static final String MEDIA_WIFI_LOCK_TAG 
= MY_PACKAGE 
+ ".WIFI_LOCK"; 
 124     /** Notification to keep in the notification bar while a song is playing */ 
 125     private NotificationManager mNotificationManager
; 
 126     private Notification mNotification 
= null
; 
 128     /** File being played */ 
 129     private OCFile mFile
; 
 131     /** Account holding the file being played */ 
 132     private Account mAccount
; 
 134     /** Flag signaling if the audio should be played immediately when the file is prepared */  
 135     protected boolean mPlayOnPrepared
; 
 137     /** Position, in miliseconds, where the audio should be started */ 
 138     private int mStartPosition
; 
 140     /** Interface to access the service through binding */ 
 141     private IBinder mBinder
; 
 143     /** Control panel shown to the user to control the playback, to register through binding */ 
 144     private MediaControlView mMediaController
; 
 149      * Helper method to get an error message suitable to show to users for errors occurred in media playback, 
 151      * @param context   A context to access string resources. 
 152      * @param what      See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int) 
 153      * @param extra     See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int) 
 154      * @return          Message suitable to users. 
 156     public static String 
getMessageForMediaError(Context context
, int what
, int extra
) { 
 159         if (what 
== OC_MEDIA_ERROR
) { 
 162         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_UNSUPPORTED
) { 
 163             /*  Added in API level 17 
 164                 Bitstream is conforming to the related coding standard or file spec, but the media framework does not support the feature. 
 165                 Constant Value: -1010 (0xfffffc0e) 
 167             messageId 
= R
.string
.media_err_unsupported
; 
 169         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_IO
) { 
 170             /*  Added in API level 17 
 171                 File or network related operation errors. 
 172                 Constant Value: -1004 (0xfffffc14)  
 174             messageId 
= R
.string
.media_err_io
; 
 176         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_MALFORMED
) { 
 177             /*  Added in API level 17 
 178                 Bitstream is not conforming to the related coding standard or file spec. 
 179                 Constant Value: -1007 (0xfffffc11)  
 181             messageId 
= R
.string
.media_err_malformed
; 
 183         } else if (extra 
== MediaPlayer
.MEDIA_ERROR_TIMED_OUT
) { 
 184             /*  Added in API level 17 
 185                 Some operation takes too long to complete, usually more than 3-5 seconds. 
 186                 Constant Value: -110 (0xffffff92) 
 188             messageId 
= R
.string
.media_err_timeout
; 
 190         } else if (what 
== MediaPlayer
.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK
) { 
 191             /*  Added in API level 3 
 192                 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. 
 193                 Constant Value: 200 (0x000000c8) 
 195             messageId 
= R
.string
.media_err_invalid_progressive_playback
; 
 198             /*  MediaPlayer.MEDIA_ERROR_UNKNOWN 
 200                 Unspecified media player error. 
 201                 Constant Value: 1 (0x00000001) 
 203             /*  MediaPlayer.MEDIA_ERROR_SERVER_DIED) 
 205                 Media server died. In this case, the application must release the MediaPlayer object and instantiate a new one. 
 206                 Constant Value: 100 (0x00000064)  
 208             messageId 
= R
.string
.media_err_unknown
; 
 210         return context
.getString(messageId
); 
 216      * Initialize a service instance 
 221     public void onCreate() { 
 223         Log_OC
.d(TAG
, "Creating ownCloud media service"); 
 225         mWifiLock 
= ((WifiManager
) getSystemService(Context
.WIFI_SERVICE
)). 
 226                 createWifiLock(WifiManager
.WIFI_MODE_FULL
, MEDIA_WIFI_LOCK_TAG
); 
 228         mNotificationManager 
= (NotificationManager
) getSystemService(NOTIFICATION_SERVICE
); 
 229         mAudioManager 
= (AudioManager
) getSystemService(AUDIO_SERVICE
); 
 230         mBinder 
= new MediaServiceBinder(this); 
 235      * Entry point for Intents requesting actions, sent here via startService. 
 240     public int onStartCommand(Intent intent
, int flags
, int startId
) { 
 241         String action 
= intent
.getAction(); 
 242         if (action
.equals(ACTION_PLAY_FILE
)) {  
 243             processPlayFileRequest(intent
); 
 245         } else if (action
.equals(ACTION_STOP_ALL
)) { 
 246             processStopRequest(true
); 
 249         return START_NOT_STICKY
; // don't want it to restart in case it's killed. 
 254      * Processes a request to play a media file received as a parameter 
 256      * TODO If a new request is received when a file is being prepared, it is ignored. Is this what we want?  
 258      * @param intent    Intent received in the request with the data to identify the file to play.  
 260     private void processPlayFileRequest(Intent intent
) { 
 261         if (mState 
!= State
.PREPARING
) { 
 262             mFile 
= intent
.getExtras().getParcelable(EXTRA_FILE
); 
 263             mAccount 
= intent
.getExtras().getParcelable(EXTRA_ACCOUNT
); 
 264             mPlayOnPrepared 
= intent
.getExtras().getBoolean(EXTRA_PLAY_ON_LOAD
, false
); 
 265             mStartPosition 
= intent
.getExtras().getInt(EXTRA_START_POSITION
, 0); 
 266             tryToGetAudioFocus(); 
 273      * Processes a request to play a media file. 
 275     protected void processPlayRequest() { 
 276         // request audio focus 
 277         tryToGetAudioFocus(); 
 279         // actually play the song 
 280         if (mState 
== State
.STOPPED
) { 
 281             // (re)start playback 
 284         } else if (mState 
== State
.PAUSED
) { 
 286             mState 
= State
.PLAYING
; 
 287             setUpAsForeground(String
.format(getString(R
.string
.media_state_playing
), mFile
.getFileName())); 
 288             configAndStartMediaPlayer(); 
 295      * Makes sure the media player exists and has been reset. This will create the media player 
 296      * if needed. reset the existing media player if one already exists. 
 298     protected void createMediaPlayerIfNeeded() { 
 299         if (mPlayer 
== null
) { 
 300             mPlayer 
= new MediaPlayer(); 
 302             // make sure the CPU won't go to sleep while media is playing 
 303             mPlayer
.setWakeMode(getApplicationContext(), PowerManager
.PARTIAL_WAKE_LOCK
); 
 305             // the media player will notify the service when it's ready preparing, and when it's done playing 
 306             mPlayer
.setOnPreparedListener(this); 
 307             mPlayer
.setOnCompletionListener(this); 
 308             mPlayer
.setOnErrorListener(this); 
 316      * Processes a request to pause the current playback  
 318     protected void processPauseRequest() { 
 319         if (mState 
== State
.PLAYING
) { 
 320             mState 
= State
.PAUSED
; 
 322             releaseResources(false
); // retain media player in pause 
 323             // TODO polite audio focus, instead of keep it owned; or not? 
 329      * Processes a request to stop the playback. 
 331      * @param   force       When 'true', the playback is stopped no matter the value of mState 
 333     protected void processStopRequest(boolean force
) { 
 334         if (mState 
!= State
.PREPARING 
|| force
) { 
 335             mState 
= State
.STOPPED
; 
 338             releaseResources(true
); 
 340             stopSelf();     // service is no longer necessary 
 346      * Releases resources used by the service for playback. This includes the "foreground service" 
 347      * status and notification, the wake locks and possibly the MediaPlayer. 
 349      * @param releaseMediaPlayer    Indicates whether the Media Player should also be released or not 
 351     protected void releaseResources(boolean releaseMediaPlayer
) { 
 352         // stop being a foreground service 
 353         stopForeground(true
); 
 355         // stop and release the Media Player, if it's available 
 356         if (releaseMediaPlayer 
&& mPlayer 
!= null
) { 
 362         // release the Wifi lock, if holding it 
 363         if (mWifiLock
.isHeld()) { 
 370      * Fully releases the audio focus. 
 372     private void giveUpAudioFocus() { 
 373         if (mAudioFocus 
== AudioFocus
.FOCUS 
 
 374                 && mAudioManager 
!= null  
 
 375                 && AudioManager
.AUDIOFOCUS_REQUEST_GRANTED 
== mAudioManager
.abandonAudioFocus(this))  { 
 377             mAudioFocus 
= AudioFocus
.NO_FOCUS
; 
 383      * Reconfigures MediaPlayer according to audio focus settings and starts/restarts it.  
 385     protected void configAndStartMediaPlayer() { 
 386         if (mPlayer 
== null
) { 
 387             throw new IllegalStateException("mPlayer is NULL"); 
 390         if (mAudioFocus 
== AudioFocus
.NO_FOCUS
) { 
 391             if (mPlayer
.isPlaying()) { 
 392                 mPlayer
.pause();        // have to be polite; but mState is not changed, to resume when focus is received again 
 396             if (mAudioFocus 
== AudioFocus
.NO_FOCUS_CAN_DUCK
) { 
 397                 mPlayer
.setVolume(DUCK_VOLUME
, DUCK_VOLUME
); 
 400                 mPlayer
.setVolume(1.0f
, 1.0f
); // full volume 
 403             if (!mPlayer
.isPlaying()) { 
 411      * Requests the audio focus to the Audio Manager  
 413     private void tryToGetAudioFocus() { 
 414         if (mAudioFocus 
!= AudioFocus
.FOCUS 
 
 415                 && mAudioManager 
!= null 
 
 416                 && (AudioManager
.AUDIOFOCUS_REQUEST_GRANTED 
== mAudioManager
.requestAudioFocus( this, 
 417                                                                                                 AudioManager
.STREAM_MUSIC
,  
 418                                                                                                 AudioManager
.AUDIOFOCUS_GAIN
)) 
 420             mAudioFocus 
= AudioFocus
.FOCUS
; 
 426      * Starts playing the current media file.  
 428     protected void playMedia() { 
 429         mState 
= State
.STOPPED
; 
 430         releaseResources(false
); // release everything except MediaPlayer 
 434                 Toast
.makeText(this, R
.string
.media_err_nothing_to_play
, Toast
.LENGTH_LONG
).show(); 
 435                 processStopRequest(true
); 
 438             } else if (mAccount 
== null
) { 
 439                 Toast
.makeText(this, R
.string
.media_err_not_in_owncloud
, Toast
.LENGTH_LONG
).show(); 
 440                 processStopRequest(true
); 
 444             createMediaPlayerIfNeeded(); 
 445             mPlayer
.setAudioStreamType(AudioManager
.STREAM_MUSIC
); 
 446             String url 
= mFile
.getStoragePath(); 
 447             /* Streaming is not possible right now 
 448             if (url == null || url.length() <= 0) { 
 449                 url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath(); 
 451             mIsStreaming = url.startsWith("http:") || url.startsWith("https:"); 
 453             mIsStreaming 
= false
; 
 455             mPlayer
.setDataSource(url
); 
 457             mState 
= State
.PREPARING
; 
 458             setUpAsForeground(String
.format(getString(R
.string
.media_state_loading
), mFile
.getFileName())); 
 460             // starts preparing the media player in background 
 461             mPlayer
.prepareAsync(); 
 463             // prevent the Wifi from going to sleep when streaming 
 466             } else if (mWifiLock
.isHeld()) { 
 470         } catch (SecurityException e
) { 
 471             Log_OC
.e(TAG
, "SecurityException playing " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 472             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_security_ex
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 473             processStopRequest(true
); 
 475         } catch (IOException e
) { 
 476             Log_OC
.e(TAG
, "IOException playing " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 477             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_io_ex
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 478             processStopRequest(true
); 
 480         } catch (IllegalStateException e
) { 
 481             Log_OC
.e(TAG
, "IllegalStateException " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 482             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_unexpected
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 483             processStopRequest(true
); 
 485         } catch (IllegalArgumentException e
) { 
 486             Log_OC
.e(TAG
, "IllegalArgumentException " + mAccount
.name 
+ mFile
.getRemotePath(), e
); 
 487             Toast
.makeText(this, String
.format(getString(R
.string
.media_err_unexpected
), mFile
.getFileName()), Toast
.LENGTH_LONG
).show(); 
 488             processStopRequest(true
); 
 493     /** Called when media player is done playing current song. */ 
 494     public void onCompletion(MediaPlayer player
) { 
 495         Toast
.makeText(this, String
.format(getString(R
.string
.media_event_done
, mFile
.getFileName())), Toast
.LENGTH_LONG
).show(); 
 496         if (mMediaController 
!= null
) { 
 497             // somebody is still bound to the service 
 499             processPauseRequest(); 
 500             mMediaController
.updatePausePlay(); 
 503             processStopRequest(true
); 
 510      * Called when media player is done preparing.  
 514     public void onPrepared(MediaPlayer player
) { 
 515         mState 
= State
.PLAYING
; 
 516         updateNotification(String
.format(getString(R
.string
.media_state_playing
), mFile
.getFileName())); 
 517         if (mMediaController 
!= null
) { 
 518             mMediaController
.setEnabled(true
); 
 520         player
.seekTo(mStartPosition
); 
 521         configAndStartMediaPlayer(); 
 522         if (!mPlayOnPrepared
) { 
 523             processPauseRequest(); 
 526         if (mMediaController 
!= null
) { 
 527             mMediaController
.updatePausePlay(); 
 533      * Updates the status notification 
 535     @SuppressWarnings("deprecation") 
 536     private void updateNotification(String content
) { 
 537         // TODO check if updating the Intent is really necessary 
 538         Intent showDetailsIntent 
= new Intent(this, FileDisplayActivity
.class); 
 539         showDetailsIntent
.putExtra(FileActivity
.EXTRA_FILE
, mFile
); 
 540         showDetailsIntent
.putExtra(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 541         showDetailsIntent
.setFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
); 
 542         mNotification
.contentIntent 
= PendingIntent
.getActivity(getApplicationContext(),  
 543                                                                 (int)System
.currentTimeMillis(),  
 545                                                                 PendingIntent
.FLAG_UPDATE_CURRENT
); 
 546         mNotification
.when 
= System
.currentTimeMillis(); 
 547         //mNotification.contentView.setTextViewText(R.id.status_text, content); 
 548         String ticker 
= String
.format(getString(R
.string
.media_notif_ticker
), getString(R
.string
.app_name
)); 
 549         mNotification
.setLatestEventInfo(getApplicationContext(), ticker
, content
, mNotification
.contentIntent
); 
 550         mNotificationManager
.notify(R
.string
.media_notif_ticker
, mNotification
); 
 555      * Configures the service as a foreground service. 
 557      * The system will avoid finishing the service as much as possible when resources as low. 
 559      * A notification must be created to keep the user aware of the existance of the service. 
 561     @SuppressWarnings("deprecation") 
 562     private void setUpAsForeground(String content
) { 
 563         /// creates status notification 
 564         // TODO put a progress bar to follow the playback progress 
 565         mNotification 
= new Notification(); 
 566         mNotification
.icon 
= android
.R
.drawable
.ic_media_play
; 
 567         //mNotification.tickerText = text; 
 568         mNotification
.when 
= System
.currentTimeMillis(); 
 569         mNotification
.flags 
|= Notification
.FLAG_ONGOING_EVENT
; 
 570         //mNotification.contentView.setTextViewText(R.id.status_text, "ownCloud Music Player");     // NULL POINTER 
 571         //mNotification.contentView.setTextViewText(R.id.status_text, getString(R.string.downloader_download_in_progress_content)); 
 574         /// includes a pending intent in the notification showing the details view of the file 
 575         Intent showDetailsIntent 
= new Intent(this, FileDisplayActivity
.class); 
 576         showDetailsIntent
.putExtra(FileActivity
.EXTRA_FILE
, mFile
); 
 577         showDetailsIntent
.putExtra(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 578         showDetailsIntent
.setFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
); 
 579         mNotification
.contentIntent 
= PendingIntent
.getActivity(getApplicationContext(),  
 580                                                                 (int)System
.currentTimeMillis(),  
 582                                                                 PendingIntent
.FLAG_UPDATE_CURRENT
); 
 585         //mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification); 
 586         String ticker 
= String
.format(getString(R
.string
.media_notif_ticker
), getString(R
.string
.app_name
)); 
 587         mNotification
.setLatestEventInfo(getApplicationContext(), ticker
, content
, mNotification
.contentIntent
); 
 588         startForeground(R
.string
.media_notif_ticker
, mNotification
); 
 593      * Called when there's an error playing media.  
 595      * Warns the user about the error and resets the media player. 
 597     public boolean onError(MediaPlayer mp
, int what
, int extra
) { 
 598         Log_OC
.e(TAG
, "Error in audio playback, what = " + what 
+ ", extra = " + extra
); 
 600         String message 
= getMessageForMediaError(this, what
, extra
); 
 601         Toast
.makeText(getApplicationContext(), message
, Toast
.LENGTH_SHORT
).show(); 
 603         processStopRequest(true
); 
 608      * Called by the system when another app tries to play some sound. 
 613     public void onAudioFocusChange(int focusChange
) { 
 614         if (focusChange 
> 0) { 
 615             // focus gain; check AudioManager.AUDIOFOCUS_* values 
 616             mAudioFocus 
= AudioFocus
.FOCUS
; 
 617             // restart media player with new focus settings 
 618             if (mState 
== State
.PLAYING
) 
 619                 configAndStartMediaPlayer(); 
 621         } else if (focusChange 
< 0) { 
 622             // focus loss; check AudioManager.AUDIOFOCUS_* values 
 623             boolean canDuck 
= AudioManager
.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 
== focusChange
; 
 624                 mAudioFocus 
= canDuck ? AudioFocus
.NO_FOCUS_CAN_DUCK 
: AudioFocus
.NO_FOCUS
; 
 625                 // start/restart/pause media player with new focus settings 
 626                 if (mPlayer 
!= null 
&& mPlayer
.isPlaying()) 
 627                     configAndStartMediaPlayer(); 
 633      * Called when the service is finished for final clean-up. 
 638     public void onDestroy() { 
 639         mState 
= State
.STOPPED
; 
 640         releaseResources(true
); 
 647      * Provides a binder object that clients can use to perform operations on the MediaPlayer managed by the MediaService.  
 650     public IBinder 
onBind(Intent arg
) { 
 656      * Called when ALL the bound clients were onbound. 
 658      * The service is destroyed if playback stopped or paused 
 661     public boolean onUnbind(Intent intent
) { 
 662         if (mState 
== State
.PAUSED 
|| mState 
== State
.STOPPED
)  { 
 663             processStopRequest(false
); 
 665         return false
;   // not accepting rebinding (default behaviour) 
 670      * Accesses the current MediaPlayer instance in the service. 
 672      * To be handled carefully. Visibility is protected to be accessed only  
 674      * @return Current MediaPlayer instance handled by MediaService. 
 676     protected MediaPlayer 
getPlayer() { 
 682      * Accesses the current OCFile loaded in the service. 
 684      * @return  The current OCFile loaded in the service. 
 686     protected OCFile 
getCurrentFile() { 
 692      * Accesses the current {@link State} of the MediaService. 
 694      * @return  The current {@link State} of the MediaService. 
 696     protected State 
getState() { 
 701     protected void setMediaContoller(MediaControlView mediaController
) { 
 702         mMediaController 
= mediaController
; 
 705     protected MediaControlView 
getMediaController() { 
 706         return mMediaController
;