X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/e4cd3fe54c8da5964936de926f61f83f027f42ef..bcc7bd2744fd3c6f6f9fb33ed46479a55914fdb9:/src/com/owncloud/android/media/MediaService.java diff --git a/src/com/owncloud/android/media/MediaService.java b/src/com/owncloud/android/media/MediaService.java index 987d94e3..5f4e1ac4 100644 --- a/src/com/owncloud/android/media/MediaService.java +++ b/src/com/owncloud/android/media/MediaService.java @@ -35,6 +35,7 @@ import android.net.wifi.WifiManager.WifiLock; import android.os.IBinder; import android.os.PowerManager; import android.util.Log; +import android.widget.MediaController; import android.widget.Toast; import java.io.IOException; @@ -66,13 +67,21 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /// 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"; + + /** 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 = 5000; + + /** 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 */ private MediaPlayer mPlayer = null; - /** Reference to the system AudioManager */ private AudioManager mAudioManager = null; @@ -121,9 +130,79 @@ public class MediaService extends Service implements OnCompletionListener, OnPre /** 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 MediaController 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,7 +245,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre * @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); tryToGetAudioFocus(); @@ -237,12 +316,10 @@ public class MediaService extends Service implements OnCompletionListener, OnPre * @param force When 'true', the playback is stopped no matter the value of mState */ protected void processStopRequest(boolean force) { - if (mState == State.PLAYING || mState == State.PAUSED || mState == State.STOPPED || force) { + if (mState != State.PREPARING || force) { mState = State.STOPPED; - mFile = null; mAccount = null; - releaseResources(true); giveUpAudioFocus(); stopSelf(); // service is no longer necessary @@ -352,10 +429,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); @@ -374,26 +454,32 @@ 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 + 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 + 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); - // TODO message to the user + 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(); - // TODO message to the user + Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show(); + processStopRequest(true); } } /** Called when media player is done playing current song. */ public void onCompletion(MediaPlayer player) { + if (mMediaController != null) { + mMediaController.hide(); + } Toast.makeText(this, String.format(getString(R.string.media_event_done, mFile.getFileName())), Toast.LENGTH_LONG).show(); processStopRequest(true); return; @@ -408,7 +494,13 @@ 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); + } configAndStartMediaPlayer(); + if (mMediaController != null) { + mMediaController.show(MEDIA_CONTROL_PERMANENT); + } } @@ -478,19 +570,19 @@ 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.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)); + if (mMediaController != null) { + mMediaController.hide(); + } - 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. * @@ -500,9 +592,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(); @@ -510,10 +600,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(); @@ -588,4 +675,17 @@ public class MediaService extends Service implements OnCompletionListener, OnPre return mState; } + + protected void setMediaContoller(MediaController mediaController) { + if (mMediaController != null) { + mMediaController.hide(); + } + mMediaController = mediaController; + + } + + protected MediaController getMediaController() { + return mMediaController; + } + }