<string name="media_err_nothing_to_play">No media file found</string>
<string name="media_err_no_account">No account provided</string>
<string name="media_err_not_in_owncloud">File not in a valid account</string>
-
+ <string name="media_err_invalid_progressive_playback">Media cannot be streamed</string>
+ <string name="media_err_unknown">Media cannot be played</string>
+ <string name="media_err_security_ex">Security error trying to play %1$s</string>
+ <string name="media_err_io_ex">Input error trying to play %1$s</string>
+ <string name="media_err_unexpected">Unexpected error tryung to playe %1$s</string>
+
<string-array name="prefs_trackmydevice_intervall_keys">
<item>15 Minutes</item>
<item>30 Minutes</item>
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
+import android.widget.MediaController;
import android.widget.Toast;
import java.io.IOException;
/// 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_LIFE = 5000;
/** 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;
/** 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;
/**
* @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();
* @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
} 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;
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_LIFE);
+ }
}
* 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));
-
- mState = State.STOPPED;
- releaseResources(true);
- giveUpAudioFocus();
+ if (mMediaController != null) {
+ mMediaController.hide();
+ }
+
+ int messageId;
+ if (what == OC_MEDIA_ERROR) {
+ messageId = extra;
+
+ } else if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
+ messageId = R.string.media_err_invalid_progressive_playback;
+
+ } else {
+ // what == MediaPlayer.MEDIA_ERROR_UNKNOWN or MEDIA_ERROR_SERVER_DIED
+ messageId = R.string.media_err_unknown;
+
+ }
+ Toast.makeText(getApplicationContext(), messageId, Toast.LENGTH_SHORT).show();
+
+ processStopRequest(true);
return true;
}
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();
} 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();
return mState;
}
+
+ protected void setMediaContoller(MediaController mediaController) {
+ if (mMediaController != null) {
+ mMediaController.hide();
+ }
+ mMediaController = mediaController;
+
+ }
+
+ protected MediaController getMediaController() {
+ return mMediaController;
+ }
+
}
mService.startService(i);
}
+
+ public void registerMediaController(MediaController mediaController) {
+ mService.setMediaContoller(mediaController);
+ }
+
+ public void unregisterMediaController(MediaController mediaController) {
+ if (mService.getMediaController() == mediaController) {
+ mService.setMediaContoller(null);
+ }
+
+ }
+
+ public boolean isInPlaybackState() {
+ MediaService.State currentState = mService.getState();
+ return (currentState == MediaService.State.PLAYING || currentState == MediaService.State.PAUSED);
+ }
+
}
--- /dev/null
+package com.owncloud.android.ui;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.widget.Toast;
+
+public class OnSwipeTouchListener implements OnTouchListener {
+
+ private final Context mContext;
+ private final GestureDetector mGestureDetector;
+
+ public OnSwipeTouchListener(Context context) {
+ mContext = context;
+ mGestureDetector = new GestureDetector(context, new GestureListener());
+ }
+
+ public boolean onTouch(final View v, final MotionEvent event) {
+ //super.onTouch(v, event);
+ Log.d("SWIPE", "Swipe listener touched");
+ return mGestureDetector.onTouchEvent(event);
+ }
+
+ private final class GestureListener extends SimpleOnGestureListener {
+
+ private static final int SWIPE_THRESHOLD = 100;
+ private static final int SWIPE_VELOCITY_THRESHOLD = 100;
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ return true;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ boolean result = false;
+ try {
+ float diffY = e2.getY() - e1.getY();
+ float diffX = e2.getX() - e1.getX();
+ if (Math.abs(diffX) > Math.abs(diffY)) {
+ if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
+ if (diffX > 0) {
+ onSwipeRight();
+ } else {
+ onSwipeLeft();
+ }
+ }
+ } else {
+ if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
+ if (diffY > 0) {
+ onSwipeBottom();
+ } else {
+ onSwipeTop();
+ }
+ }
+ }
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+ return result;
+ }
+ }
+
+ public void onSwipeTop() {
+ Toast.makeText(mContext, "top", Toast.LENGTH_SHORT).show();
+ }
+ public void onSwipeRight() {
+ Toast.makeText(mContext, "right", Toast.LENGTH_SHORT).show();
+ }
+ public void onSwipeLeft() {
+ Toast.makeText(mContext, "left", Toast.LENGTH_SHORT).show();
+ }
+ public void onSwipeBottom() {
+ Toast.makeText(mContext, "bottom", Toast.LENGTH_SHORT).show();
+ }
+
+}
+
import com.owncloud.android.AccountUtils;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.media.MediaService;
/**
* Activity implementing a basic video player.
/** Key to receive the ownCloud {@link Account} where the file to play is saved as an extra value in an {@link Intent} */
public static final String EXTRA_ACCOUNT = "ACCOUNT";
- // Time To keep the control panel visible when the user does not use it
- private static final int MEDIA_CONTOL_LIFE = 5000;
-
- private static final int OC_MEDIA_ERROR = 0;
private static final String TAG = null;
private OCFile mFile; // video file to play
mVideoPlayer.setVideoURI(Uri.parse(url));
} else {
- onError(null, OC_MEDIA_ERROR, R.string.media_err_no_account);
+ onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_no_account);
}
// create and prepare control panel for the user
mVideoPlayer.setMediaController(mMediaController);
} else {
- onError(null, OC_MEDIA_ERROR, R.string.media_err_nothing_to_play);
+ onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_nothing_to_play);
}
}
*/
@Override
public void onPrepared(MediaPlayer vp) {
- mVideoPlayer.start(); // TODO maybe unnecessary
- //mMediaController.show(5000); // TODO maybe unnecessary; maybe not, it's up when the Surface notifies the VideoView about creation
+ mVideoPlayer.start();
+ mMediaController.show(5000);
}
if (mVideoPlayer.getWindowToken() != null) {
int messageId;
- if (what == OC_MEDIA_ERROR) {
+ if (what == MediaService.OC_MEDIA_ERROR) {
messageId = extra;
} else if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
@Override
public boolean onTouchEvent (MotionEvent ev){
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mMediaController.show(MEDIA_CONTOL_LIFE);
+ mMediaController.show(MediaService.MEDIA_CONTROL_LIFE);
return true;
} else {
return false;
import com.owncloud.android.ui.activity.ConflictsResolveActivity;\r
import com.owncloud.android.ui.activity.FileDetailActivity;\r
import com.owncloud.android.ui.activity.FileDisplayActivity;\r
+import com.owncloud.android.ui.OnSwipeTouchListener;\r
import com.owncloud.android.ui.activity.TransferServiceGetter;\r
import com.owncloud.android.ui.activity.VideoActivity;\r
import com.owncloud.android.ui.dialog.EditNameDialog;\r
* This Fragment is used to display the details about a file.\r
* \r
* @author Bartek Przybylski\r
- * \r
+ * @author David A. Velasco\r
*/\r
public class FileDetailFragment extends SherlockFragment implements\r
OnClickListener, OnTouchListener, \r
super.onAttach(activity);\r
try {\r
mContainerActivity = (ContainerActivity) activity;\r
+ \r
} catch (ClassCastException e) {\r
throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());\r
}\r
super.onActivityCreated(savedInstanceState);\r
if (mAccount != null) {\r
mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;\r
+ mView.setOnTouchListener(new OnSwipeTouchListener(getActivity())); \r
}\r
}\r
\r
\r
mPreview = (ImageView)mView.findViewById(R.id.fdPreview); // this is here just because it is nullified in onPause()\r
\r
- if (mMediaController != null) {\r
- mMediaController.show();\r
- }\r
}\r
\r
\r
mPreview = null;\r
}\r
\r
- if (mMediaController != null) {\r
- mMediaController.hide();\r
- }\r
}\r
\r
\r
super.onStop();\r
if (mMediaServiceConnection != null) {\r
Log.d(TAG, "Unbinding from MediaService ...");\r
+ if (mMediaServiceBinder != null && mMediaController != null) {\r
+ mMediaServiceBinder.unregisterMediaController(mMediaController);\r
+ }\r
getActivity().unbindService(mMediaServiceConnection);\r
mMediaServiceBinder = null;\r
- mMediaController = null;\r
+ if (mMediaController != null) {\r
+ mMediaController.hide();\r
+ mMediaController = null;\r
+ }\r
}\r
}\r
\r
Log.d(TAG, "starting playback of " + mFile.getStoragePath());\r
mMediaServiceBinder.start(mAccount, mFile);\r
// this is a patch; need to synchronize this with the onPrepared() coming from MediaPlayer in the MediaService\r
+ /*\r
mMediaController.postDelayed(new Runnable() {\r
@Override\r
public void run() {\r
mMediaController.show(0);\r
}\r
} , 300);\r
+ */\r
} else {\r
- mMediaController.show(0);\r
+ if (mMediaController.isShowing()) {\r
+ mMediaController.hide();\r
+ } else {\r
+ mMediaController.show(MediaService.MEDIA_CONTROL_LIFE);\r
+ }\r
}\r
\r
} else if (mFile.isVideo()) {\r
i.putExtra(VideoActivity.EXTRA_FILE, mFile);\r
i.putExtra(VideoActivity.EXTRA_ACCOUNT, mAccount);\r
startActivity(i);\r
- \r
- // TODO THROW AN ACTIVTIY JUST FOR PREVIEW VIDEO\r
- /*\r
- if (mMediaController == null) {\r
- mMediaController = new MediaController(getActivity());\r
- mMediaController.setAnchorView(mVideoPreview);\r
- //mMediaController.setEnabled(true);\r
- }\r
- //mMediaController.setMediaPlayer(mMediaServiceBinder);\r
- if (!mVideoPreviewIsLoaded) {\r
- mVideoPreviewIsLoaded = true;\r
- mMediaController.setMediaPlayer(mVideoPreview);\r
- mVideoPreview.setMediaController(mMediaController);\r
- mVideoPreview.setVideoPath(mFile.getStoragePath());\r
- mVideoPreview.start();\r
- //mMediaController.show(0);\r
- } else {\r
- mMediaController.show(0);\r
- }*/\r
}\r
\r
\r
if (mMediaController == null) {\r
mMediaController = new MediaController(getSherlockActivity());\r
}\r
- mMediaController.setMediaPlayer(mMediaServiceBinder);\r
- mMediaController.setAnchorView(mPreview);\r
- mMediaController.setEnabled(true);\r
+ prepareMediaController();\r
\r
Log.d(TAG, "Successfully bound to MediaService, MediaController ready");\r
\r
}\r
}\r
\r
+ private void prepareMediaController() {\r
+ mMediaServiceBinder.registerMediaController(mMediaController);\r
+ mMediaController.setMediaPlayer(mMediaServiceBinder);\r
+ mMediaController.setAnchorView(getView());\r
+ mMediaController.setEnabled(mMediaServiceBinder.isInPlaybackState());\r
+ }\r
+\r
@Override\r
public void onServiceDisconnected(ComponentName component) {\r
if (component.equals(new ComponentName(getActivity(), MediaService.class))) {\r
- Log.d(TAG, "Media service suddenly disconnected");\r
+ Log.e(TAG, "Media service suddenly disconnected");\r
if (mMediaController != null) {\r
mMediaController.hide();\r
- mMediaController.setMediaPlayer(null); // TODO check this is not an error\r
+ mMediaController.setMediaPlayer(null);\r
mMediaController = null;\r
}\r
mMediaServiceBinder = null;\r