2013-02-14 22:21:09 +04:00
/ * ownCloud Android client application
* Copyright ( C ) 2012 - 2013 ownCloud Inc .
*
* This program is free software : you can redistribute it and / or modify
2013-04-17 14:26:13 +04:00
* it under the terms of the GNU General Public License version 2 ,
* as published by the Free Software Foundation .
2013-02-14 22:21:09 +04:00
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* /
2013-02-26 22:04:42 +04:00
package com.owncloud.android.ui.preview ;
2013-02-14 22:21:09 +04:00
import java.io.File ;
import java.util.ArrayList ;
import java.util.List ;
import android.accounts.Account ;
import android.app.Activity ;
import android.app.AlertDialog ;
import android.content.ActivityNotFoundException ;
import android.content.ComponentName ;
import android.content.Context ;
import android.content.DialogInterface ;
import android.content.Intent ;
import android.content.ServiceConnection ;
2013-04-30 15:16:08 +04:00
import android.content.res.Configuration ;
2013-02-14 22:21:09 +04:00
import android.media.MediaPlayer ;
import android.media.MediaPlayer.OnCompletionListener ;
import android.media.MediaPlayer.OnErrorListener ;
import android.media.MediaPlayer.OnPreparedListener ;
import android.net.Uri ;
2013-04-10 15:07:10 +04:00
import android.os.Build ;
2013-02-14 22:21:09 +04:00
import android.os.Bundle ;
import android.os.Handler ;
import android.os.IBinder ;
import android.view.LayoutInflater ;
import android.view.MotionEvent ;
import android.view.View ;
import android.view.View.OnTouchListener ;
import android.view.ViewGroup ;
import android.webkit.MimeTypeMap ;
import android.widget.ImageView ;
import android.widget.Toast ;
import android.widget.VideoView ;
2013-02-18 14:23:18 +04:00
import com.actionbarsherlock.view.Menu ;
import com.actionbarsherlock.view.MenuInflater ;
import com.actionbarsherlock.view.MenuItem ;
2013-02-14 22:21:09 +04:00
import com.owncloud.android.datamodel.FileDataStorageManager ;
import com.owncloud.android.datamodel.OCFile ;
2013-03-08 16:32:10 +04:00
import com.owncloud.android.media.MediaControlView ;
2013-02-14 22:21:09 +04:00
import com.owncloud.android.media.MediaService ;
import com.owncloud.android.media.MediaServiceBinder ;
import com.owncloud.android.operations.OnRemoteOperationListener ;
import com.owncloud.android.operations.RemoteOperation ;
import com.owncloud.android.operations.RemoteOperationResult ;
import com.owncloud.android.operations.RemoveFileOperation ;
2013-06-14 18:59:38 +04:00
import com.owncloud.android.ui.activity.FileActivity ;
2013-02-14 22:21:09 +04:00
import com.owncloud.android.ui.activity.FileDisplayActivity ;
2013-02-26 22:04:42 +04:00
import com.owncloud.android.ui.fragment.ConfirmationDialogFragment ;
import com.owncloud.android.ui.fragment.FileFragment ;
2013-02-14 22:21:09 +04:00
2013-04-30 15:16:08 +04:00
import com.owncloud.android.Log_OC ;
2013-02-14 22:21:09 +04:00
import com.owncloud.android.R ;
import eu.alefzero.webdav.WebdavUtils ;
/ * *
2013-02-26 22:04:42 +04:00
* This fragment shows a preview of a downloaded media file ( audio or video ) .
2013-02-14 22:21:09 +04:00
*
* Trying to get an instance with NULL { @link OCFile } or ownCloud { @link Account } values will produce an { @link IllegalStateException } .
*
* By now , if the { @link OCFile } passed is not downloaded , an { @link IllegalStateException } is generated on instantiation too .
*
* @author David A . Velasco
* /
2013-05-30 19:53:21 +04:00
public class PreviewMediaFragment extends FileFragment implements
OnTouchListener ,
2013-02-26 22:04:42 +04:00
ConfirmationDialogFragment . ConfirmationDialogFragmentListener , OnRemoteOperationListener {
2013-02-14 22:21:09 +04:00
public static final String EXTRA_FILE = " FILE " ;
public static final String EXTRA_ACCOUNT = " ACCOUNT " ;
private static final String EXTRA_PLAY_POSITION = " PLAY_POSITION " ;
2013-03-13 15:21:33 +04:00
private static final String EXTRA_PLAYING = " PLAYING " ;
2013-02-14 22:21:09 +04:00
private View mView ;
private Account mAccount ;
2013-02-18 14:23:18 +04:00
private FileDataStorageManager mStorageManager ;
2013-02-14 22:21:09 +04:00
private ImageView mImagePreview ;
private VideoView mVideoPreview ;
private int mSavedPlaybackPosition ;
2013-02-18 14:23:18 +04:00
private Handler mHandler ;
private RemoteOperation mLastRemoteOperation ;
2013-02-14 22:21:09 +04:00
private MediaServiceBinder mMediaServiceBinder = null ;
2013-03-08 16:32:10 +04:00
private MediaControlView mMediaController = null ;
2013-02-14 22:21:09 +04:00
private MediaServiceConnection mMediaServiceConnection = null ;
private VideoHelper mVideoHelper ;
2013-03-13 15:21:33 +04:00
private boolean mAutoplay ;
2013-04-30 15:16:08 +04:00
public boolean mPrepared ;
2013-02-14 22:21:09 +04:00
2013-02-26 22:04:42 +04:00
private static final String TAG = PreviewMediaFragment . class . getSimpleName ( ) ;
2013-02-14 22:21:09 +04:00
/ * *
* Creates a fragment to preview a file .
*
* When ' fileToDetail ' or ' ocAccount ' are null
*
* @param fileToDetail An { @link OCFile } to preview in the fragment
* @param ocAccount An ownCloud account ; needed to start downloads
* /
2013-04-26 16:02:17 +04:00
public PreviewMediaFragment ( OCFile fileToDetail , Account ocAccount , int startPlaybackPosition , boolean autoplay ) {
2013-05-30 19:53:21 +04:00
super ( fileToDetail ) ;
2013-02-14 22:21:09 +04:00
mAccount = ocAccount ;
2013-04-26 16:02:17 +04:00
mSavedPlaybackPosition = startPlaybackPosition ;
2013-02-18 14:23:18 +04:00
mStorageManager = null ; // we need a context to init this; the container activity is not available yet at this moment
2013-04-26 16:02:17 +04:00
mAutoplay = autoplay ;
2013-02-14 22:21:09 +04:00
}
/ * *
* Creates an empty fragment for previews .
*
* MUST BE KEPT : the system uses it when tries to reinstantiate a fragment automatically ( for instance , when the device is turned a aside ) .
*
* DO NOT CALL IT : an { @link OCFile } and { @link Account } must be provided for a successful construction
* /
2013-02-26 22:04:42 +04:00
public PreviewMediaFragment ( ) {
2013-05-30 19:53:21 +04:00
super ( ) ;
2013-02-14 22:21:09 +04:00
mAccount = null ;
mSavedPlaybackPosition = 0 ;
2013-02-18 14:23:18 +04:00
mStorageManager = null ;
2013-03-13 15:21:33 +04:00
mAutoplay = true ;
2013-02-14 22:21:09 +04:00
}
/ * *
* { @inheritDoc }
* /
@Override
public void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState ) ;
2013-02-18 14:23:18 +04:00
mHandler = new Handler ( ) ;
setHasOptionsMenu ( true ) ;
2013-02-14 22:21:09 +04:00
}
/ * *
* { @inheritDoc }
* /
@Override
public View onCreateView ( LayoutInflater inflater , ViewGroup container ,
Bundle savedInstanceState ) {
super . onCreateView ( inflater , container , savedInstanceState ) ;
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onCreateView " ) ;
2013-02-14 22:21:09 +04:00
mView = inflater . inflate ( R . layout . file_preview , container , false ) ;
mImagePreview = ( ImageView ) mView . findViewById ( R . id . image_preview ) ;
mVideoPreview = ( VideoView ) mView . findViewById ( R . id . video_preview ) ;
2013-03-14 19:55:57 +04:00
mVideoPreview . setOnTouchListener ( this ) ;
2013-02-14 22:21:09 +04:00
2013-03-08 16:32:10 +04:00
mMediaController = ( MediaControlView ) mView . findViewById ( R . id . media_controller ) ;
2013-02-14 22:21:09 +04:00
return mView ;
}
/ * *
* { @inheritDoc }
* /
@Override
public void onAttach ( Activity activity ) {
super . onAttach ( activity ) ;
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onAttach " ) ;
2013-02-18 14:23:18 +04:00
if ( ! ( activity instanceof FileFragment . ContainerActivity ) )
throw new ClassCastException ( activity . toString ( ) + " must implement " + FileFragment . ContainerActivity . class . getSimpleName ( ) ) ;
2013-02-14 22:21:09 +04:00
}
/ * *
* { @inheritDoc }
* /
@Override
public void onActivityCreated ( Bundle savedInstanceState ) {
super . onActivityCreated ( savedInstanceState ) ;
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onActivityCreated " ) ;
2013-02-14 22:21:09 +04:00
2013-02-18 14:23:18 +04:00
mStorageManager = new FileDataStorageManager ( mAccount , getActivity ( ) . getApplicationContext ( ) . getContentResolver ( ) ) ;
2013-02-14 22:21:09 +04:00
if ( savedInstanceState ! = null ) {
2013-05-30 19:53:21 +04:00
setFile ( ( OCFile ) savedInstanceState . getParcelable ( PreviewMediaFragment . EXTRA_FILE ) ) ;
2013-02-26 22:04:42 +04:00
mAccount = savedInstanceState . getParcelable ( PreviewMediaFragment . EXTRA_ACCOUNT ) ;
mSavedPlaybackPosition = savedInstanceState . getInt ( PreviewMediaFragment . EXTRA_PLAY_POSITION ) ;
2013-03-13 15:21:33 +04:00
mAutoplay = savedInstanceState . getBoolean ( PreviewMediaFragment . EXTRA_PLAYING ) ;
2013-02-14 22:21:09 +04:00
}
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
if ( file = = null ) {
2013-02-14 22:21:09 +04:00
throw new IllegalStateException ( " Instanced with a NULL OCFile " ) ;
}
if ( mAccount = = null ) {
throw new IllegalStateException ( " Instanced with a NULL ownCloud Account " ) ;
}
2013-05-30 19:53:21 +04:00
if ( ! file . isDown ( ) ) {
2013-02-14 22:21:09 +04:00
throw new IllegalStateException ( " There is no local file to preview " ) ;
}
2013-05-30 19:53:21 +04:00
if ( file . isVideo ( ) ) {
2013-02-14 22:21:09 +04:00
mVideoPreview . setVisibility ( View . VISIBLE ) ;
mImagePreview . setVisibility ( View . GONE ) ;
prepareVideo ( ) ;
} else {
mVideoPreview . setVisibility ( View . GONE ) ;
mImagePreview . setVisibility ( View . VISIBLE ) ;
}
}
/ * *
* { @inheritDoc }
* /
@Override
public void onSaveInstanceState ( Bundle outState ) {
super . onSaveInstanceState ( outState ) ;
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onSaveInstanceState " ) ;
2013-05-30 19:53:21 +04:00
outState . putParcelable ( PreviewMediaFragment . EXTRA_FILE , getFile ( ) ) ;
2013-02-26 22:04:42 +04:00
outState . putParcelable ( PreviewMediaFragment . EXTRA_ACCOUNT , mAccount ) ;
2013-02-14 22:21:09 +04:00
2013-05-30 19:53:21 +04:00
if ( getFile ( ) . isVideo ( ) ) {
2013-04-11 18:56:51 +04:00
mSavedPlaybackPosition = mVideoPreview . getCurrentPosition ( ) ;
mAutoplay = mVideoPreview . isPlaying ( ) ;
outState . putInt ( PreviewMediaFragment . EXTRA_PLAY_POSITION , mSavedPlaybackPosition ) ;
outState . putBoolean ( PreviewMediaFragment . EXTRA_PLAYING , mAutoplay ) ;
2013-03-22 16:04:57 +04:00
} else {
outState . putInt ( PreviewMediaFragment . EXTRA_PLAY_POSITION , mMediaServiceBinder . getCurrentPosition ( ) ) ;
outState . putBoolean ( PreviewMediaFragment . EXTRA_PLAYING , mMediaServiceBinder . isPlaying ( ) ) ;
2013-02-14 22:21:09 +04:00
}
}
@Override
public void onStart ( ) {
super . onStart ( ) ;
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onStart " ) ;
2013-02-14 22:21:09 +04:00
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
if ( file ! = null ) {
if ( file . isAudio ( ) ) {
2013-02-14 22:21:09 +04:00
bindMediaService ( ) ;
2013-05-30 19:53:21 +04:00
} else if ( file . isVideo ( ) ) {
2013-03-07 20:07:58 +04:00
stopAudio ( ) ;
2013-02-14 22:21:09 +04:00
playVideo ( ) ;
}
}
}
2013-03-07 20:07:58 +04:00
private void stopAudio ( ) {
Intent i = new Intent ( getSherlockActivity ( ) , MediaService . class ) ;
i . setAction ( MediaService . ACTION_STOP_ALL ) ;
getSherlockActivity ( ) . startService ( i ) ;
}
2013-02-18 14:23:18 +04:00
/ * *
* { @inheritDoc }
* /
@Override
public void onCreateOptionsMenu ( Menu menu , MenuInflater inflater ) {
super . onCreateOptionsMenu ( menu , inflater ) ;
inflater . inflate ( R . menu . file_actions_menu , menu ) ;
List < Integer > toHide = new ArrayList < Integer > ( ) ;
MenuItem item = null ;
toHide . add ( R . id . action_cancel_download ) ;
toHide . add ( R . id . action_cancel_upload ) ;
toHide . add ( R . id . action_download_file ) ;
2013-04-22 16:34:42 +04:00
toHide . add ( R . id . action_sync_file ) ;
2013-02-18 14:23:18 +04:00
toHide . add ( R . id . action_rename_file ) ; // by now
for ( int i : toHide ) {
item = menu . findItem ( i ) ;
if ( item ! = null ) {
item . setVisible ( false ) ;
item . setEnabled ( false ) ;
}
}
}
/ * *
* { @inheritDoc }
* /
@Override
public boolean onOptionsItemSelected ( MenuItem item ) {
switch ( item . getItemId ( ) ) {
case R . id . action_open_file_with : {
openFile ( ) ;
return true ;
}
case R . id . action_remove_file : {
removeFile ( ) ;
return true ;
}
case R . id . action_see_details : {
seeDetails ( ) ;
return true ;
}
default :
return false ;
}
}
private void seeDetails ( ) {
stopPreview ( false ) ;
2013-05-30 19:53:21 +04:00
( ( FileFragment . ContainerActivity ) getActivity ( ) ) . showDetails ( getFile ( ) ) ;
2013-02-18 14:23:18 +04:00
}
2013-02-14 22:21:09 +04:00
private void prepareVideo ( ) {
// create helper to get more control on the playback
2013-02-15 12:58:53 +04:00
mVideoHelper = new VideoHelper ( ) ;
2013-02-14 22:21:09 +04:00
mVideoPreview . setOnPreparedListener ( mVideoHelper ) ;
mVideoPreview . setOnCompletionListener ( mVideoHelper ) ;
mVideoPreview . setOnErrorListener ( mVideoHelper ) ;
}
private void playVideo ( ) {
2013-03-11 13:20:04 +04:00
// create and prepare control panel for the user
mMediaController . setMediaPlayer ( mVideoPreview ) ;
2013-02-14 22:21:09 +04:00
// load the video file in the video player ; when done, VideoHelper#onPrepared() will be called
2013-05-30 19:53:21 +04:00
mVideoPreview . setVideoPath ( getFile ( ) . getStoragePath ( ) ) ;
2013-02-14 22:21:09 +04:00
}
private class VideoHelper implements OnCompletionListener , OnPreparedListener , OnErrorListener {
/ * *
* Called when the file is ready to be played .
*
* Just starts the playback .
*
* @param mp { @link MediaPlayer } instance performing the playback .
* /
@Override
public void onPrepared ( MediaPlayer vp ) {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " onPrepared " ) ;
2013-02-14 22:21:09 +04:00
mVideoPreview . seekTo ( mSavedPlaybackPosition ) ;
2013-03-13 15:21:33 +04:00
if ( mAutoplay ) {
mVideoPreview . start ( ) ;
}
2013-03-11 13:20:04 +04:00
mMediaController . setEnabled ( true ) ;
mMediaController . updatePausePlay ( ) ;
2013-04-30 15:16:08 +04:00
mPrepared = true ;
2013-02-14 22:21:09 +04:00
}
/ * *
* Called when the file is finished playing .
*
* Finishes the activity .
*
* @param mp { @link MediaPlayer } instance performing the playback .
* /
@Override
public void onCompletion ( MediaPlayer mp ) {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " completed " ) ;
2013-04-10 15:07:10 +04:00
if ( mp ! = null ) {
mVideoPreview . seekTo ( 0 ) ;
// next lines are necessary to work around undesired video loops
if ( Build . VERSION . SDK_INT = = Build . VERSION_CODES . GINGERBREAD ) {
mVideoPreview . pause ( ) ;
} else if ( Build . VERSION . SDK_INT = = Build . VERSION_CODES . GINGERBREAD_MR1 ) {
// mVideePreview.pause() is not enough
mMediaController . setEnabled ( false ) ;
mVideoPreview . stopPlayback ( ) ;
mAutoplay = false ;
mSavedPlaybackPosition = 0 ;
2013-05-30 19:53:21 +04:00
mVideoPreview . setVideoPath ( getFile ( ) . getStoragePath ( ) ) ;
2013-04-10 15:07:10 +04:00
}
} // else : called from onError()
2013-03-14 19:55:57 +04:00
mMediaController . updatePausePlay ( ) ;
2013-02-14 22:21:09 +04:00
}
/ * *
* Called when an error in playback occurs .
*
* @param mp { @link MediaPlayer } instance performing the playback .
* @param what Type of error
* @param extra Extra code specific to the error
* /
@Override
public boolean onError ( MediaPlayer mp , int what , int extra ) {
if ( mVideoPreview . getWindowToken ( ) ! = null ) {
String message = MediaService . getMessageForMediaError ( getActivity ( ) , what , extra ) ;
new AlertDialog . Builder ( getActivity ( ) )
. setMessage ( message )
. setPositiveButton ( android . R . string . VideoView_error_button ,
new DialogInterface . OnClickListener ( ) {
public void onClick ( DialogInterface dialog , int whichButton ) {
dialog . dismiss ( ) ;
VideoHelper . this . onCompletion ( null ) ;
}
} )
. setCancelable ( false )
. show ( ) ;
}
return true ;
}
}
2013-04-30 15:16:08 +04:00
@Override
public void onPause ( ) {
super . onPause ( ) ;
Log_OC . e ( TAG , " onPause " ) ;
}
@Override
public void onResume ( ) {
super . onResume ( ) ;
Log_OC . e ( TAG , " onResume " ) ;
}
@Override
public void onDestroy ( ) {
super . onDestroy ( ) ;
Log_OC . e ( TAG , " onDestroy " ) ;
}
2013-02-14 22:21:09 +04:00
@Override
public void onStop ( ) {
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onStop " ) ;
2013-02-14 22:21:09 +04:00
super . onStop ( ) ;
2013-04-30 15:16:08 +04:00
mPrepared = false ;
2013-02-14 22:21:09 +04:00
if ( mMediaServiceConnection ! = null ) {
2013-04-25 21:39:22 +04:00
Log_OC . d ( TAG , " Unbinding from MediaService ... " ) ;
2013-02-14 22:21:09 +04:00
if ( mMediaServiceBinder ! = null & & mMediaController ! = null ) {
2013-03-12 17:36:31 +04:00
mMediaServiceBinder . unregisterMediaController ( mMediaController ) ;
2013-02-14 22:21:09 +04:00
}
getActivity ( ) . unbindService ( mMediaServiceConnection ) ;
mMediaServiceConnection = null ;
mMediaServiceBinder = null ;
}
2013-02-18 14:23:18 +04:00
}
2013-02-14 22:21:09 +04:00
@Override
public boolean onTouch ( View v , MotionEvent event ) {
2013-03-14 19:55:57 +04:00
if ( event . getAction ( ) = = MotionEvent . ACTION_DOWN & & v = = mVideoPreview ) {
startFullScreenVideo ( ) ;
return true ;
2013-02-14 22:21:09 +04:00
}
return false ;
}
2013-03-14 19:55:57 +04:00
private void startFullScreenVideo ( ) {
Intent i = new Intent ( getActivity ( ) , PreviewVideoActivity . class ) ;
2013-06-14 18:59:38 +04:00
i . putExtra ( FileActivity . EXTRA_ACCOUNT , mAccount ) ;
i . putExtra ( FileActivity . EXTRA_FILE , getFile ( ) ) ;
2013-03-14 19:55:57 +04:00
i . putExtra ( PreviewVideoActivity . EXTRA_AUTOPLAY , mVideoPreview . isPlaying ( ) ) ;
mVideoPreview . pause ( ) ;
i . putExtra ( PreviewVideoActivity . EXTRA_START_POSITION , mVideoPreview . getCurrentPosition ( ) ) ;
startActivityForResult ( i , 0 ) ;
2013-02-14 22:21:09 +04:00
}
2013-04-30 15:16:08 +04:00
@Override
public void onConfigurationChanged ( Configuration newConfig ) {
Log_OC . e ( TAG , " onConfigurationChanged " + this ) ;
}
2013-03-14 19:55:57 +04:00
@Override
public void onActivityResult ( int requestCode , int resultCode , Intent data ) {
2013-04-30 15:16:08 +04:00
Log_OC . e ( TAG , " onActivityResult " + this ) ;
2013-03-14 19:55:57 +04:00
super . onActivityResult ( requestCode , resultCode , data ) ;
if ( resultCode = = Activity . RESULT_OK ) {
mSavedPlaybackPosition = data . getExtras ( ) . getInt ( PreviewVideoActivity . EXTRA_START_POSITION ) ;
mAutoplay = data . getExtras ( ) . getBoolean ( PreviewVideoActivity . EXTRA_AUTOPLAY ) ;
}
}
2013-02-14 22:21:09 +04:00
private void playAudio ( ) {
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
if ( ! mMediaServiceBinder . isPlaying ( file ) ) {
Log_OC . d ( TAG , " starting playback of " + file . getStoragePath ( ) ) ;
mMediaServiceBinder . start ( mAccount , file , mAutoplay , mSavedPlaybackPosition ) ;
2013-02-14 22:21:09 +04:00
} else {
2013-03-22 16:04:57 +04:00
if ( ! mMediaServiceBinder . isPlaying ( ) & & mAutoplay ) {
2013-02-14 22:21:09 +04:00
mMediaServiceBinder . start ( ) ;
2013-03-12 17:36:31 +04:00
mMediaController . updatePausePlay ( ) ;
2013-02-14 22:21:09 +04:00
}
}
}
private void bindMediaService ( ) {
2013-04-25 21:39:22 +04:00
Log_OC . d ( TAG , " Binding to MediaService... " ) ;
2013-02-14 22:21:09 +04:00
if ( mMediaServiceConnection = = null ) {
mMediaServiceConnection = new MediaServiceConnection ( ) ;
}
getActivity ( ) . bindService ( new Intent ( getActivity ( ) ,
MediaService . class ) ,
mMediaServiceConnection ,
Context . BIND_AUTO_CREATE ) ;
// follow the flow in MediaServiceConnection#onServiceConnected(...)
}
/** Defines callbacks for service binding, passed to bindService() */
private class MediaServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected ( ComponentName component , IBinder service ) {
if ( component . equals ( new ComponentName ( getActivity ( ) , MediaService . class ) ) ) {
2013-04-25 21:39:22 +04:00
Log_OC . d ( TAG , " Media service connected " ) ;
2013-02-14 22:21:09 +04:00
mMediaServiceBinder = ( MediaServiceBinder ) service ;
if ( mMediaServiceBinder ! = null ) {
prepareMediaController ( ) ;
playAudio ( ) ; // do not wait for the touch of nobody to play audio
2013-04-25 21:39:22 +04:00
Log_OC . d ( TAG , " Successfully bound to MediaService, MediaController ready " ) ;
2013-02-14 22:21:09 +04:00
} else {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " Unexpected response from MediaService while binding " ) ;
2013-02-14 22:21:09 +04:00
}
}
}
2013-03-12 17:36:31 +04:00
2013-02-14 22:21:09 +04:00
private void prepareMediaController ( ) {
2013-03-12 17:36:31 +04:00
mMediaServiceBinder . registerMediaController ( mMediaController ) ;
2013-03-08 16:32:10 +04:00
if ( mMediaController ! = null ) {
mMediaController . setMediaPlayer ( mMediaServiceBinder ) ;
2013-03-11 13:20:04 +04:00
mMediaController . setEnabled ( true ) ;
mMediaController . updatePausePlay ( ) ;
2013-03-08 16:32:10 +04:00
}
2013-02-14 22:21:09 +04:00
}
@Override
public void onServiceDisconnected ( ComponentName component ) {
if ( component . equals ( new ComponentName ( getActivity ( ) , MediaService . class ) ) ) {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " Media service suddenly disconnected " ) ;
2013-02-14 22:21:09 +04:00
if ( mMediaController ! = null ) {
mMediaController . setMediaPlayer ( null ) ;
2013-03-08 16:32:10 +04:00
} else {
Toast . makeText ( getActivity ( ) , " No media controller to release when disconnected from media service " , Toast . LENGTH_SHORT ) . show ( ) ;
2013-02-14 22:21:09 +04:00
}
mMediaServiceBinder = null ;
mMediaServiceConnection = null ;
}
}
}
2013-02-18 14:23:18 +04:00
/ * *
* Opens the previewed file with an external application .
*
* TODO - improve this ; instead of prioritize the actions available for the MIME type in the server ,
* we should get a list of available apps for MIME tpye in the server and join it with the list of
* available apps for the MIME type known from the file extension , to let the user choose
* /
2013-02-14 22:21:09 +04:00
private void openFile ( ) {
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
2013-02-18 14:23:18 +04:00
stopPreview ( true ) ;
2013-05-30 19:53:21 +04:00
String storagePath = file . getStoragePath ( ) ;
2013-02-14 22:21:09 +04:00
String encodedStoragePath = WebdavUtils . encodePath ( storagePath ) ;
try {
Intent i = new Intent ( Intent . ACTION_VIEW ) ;
2013-05-30 19:53:21 +04:00
i . setDataAndType ( Uri . parse ( " file:// " + encodedStoragePath ) , file . getMimetype ( ) ) ;
2013-02-14 22:21:09 +04:00
i . setFlags ( Intent . FLAG_GRANT_READ_URI_PERMISSION | Intent . FLAG_GRANT_WRITE_URI_PERMISSION ) ;
startActivity ( i ) ;
} catch ( Throwable t ) {
2013-05-30 19:53:21 +04:00
Log_OC . e ( TAG , " Fail when trying to open with the mimeType provided from the ownCloud server: " + file . getMimetype ( ) ) ;
2013-02-14 22:21:09 +04:00
boolean toastIt = true ;
String mimeType = " " ;
try {
Intent i = new Intent ( Intent . ACTION_VIEW ) ;
mimeType = MimeTypeMap . getSingleton ( ) . getMimeTypeFromExtension ( storagePath . substring ( storagePath . lastIndexOf ( '.' ) + 1 ) ) ;
2013-05-30 19:53:21 +04:00
if ( mimeType = = null | | ! mimeType . equals ( file . getMimetype ( ) ) ) {
2013-02-14 22:21:09 +04:00
if ( mimeType ! = null ) {
i . setDataAndType ( Uri . parse ( " file:// " + encodedStoragePath ) , mimeType ) ;
} else {
// desperate try
i . setDataAndType ( Uri . parse ( " file:// " + encodedStoragePath ) , " *-/* " ) ;
}
i . setFlags ( Intent . FLAG_GRANT_READ_URI_PERMISSION | Intent . FLAG_GRANT_WRITE_URI_PERMISSION ) ;
startActivity ( i ) ;
toastIt = false ;
}
} catch ( IndexOutOfBoundsException e ) {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " Trying to find out MIME type of a file without extension: " + storagePath ) ;
2013-02-14 22:21:09 +04:00
} catch ( ActivityNotFoundException e ) {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension " ) ;
2013-02-14 22:21:09 +04:00
} catch ( Throwable th ) {
2013-04-25 21:39:22 +04:00
Log_OC . e ( TAG , " Unexpected problem when opening: " + storagePath , th ) ;
2013-02-14 22:21:09 +04:00
} finally {
if ( toastIt ) {
2013-05-30 19:53:21 +04:00
Toast . makeText ( getActivity ( ) , " There is no application to handle file " + file . getFileName ( ) , Toast . LENGTH_SHORT ) . show ( ) ;
2013-02-14 22:21:09 +04:00
}
}
}
2013-02-18 14:23:18 +04:00
finish ( ) ;
}
/ * *
* Starts a the removal of the previewed file .
*
* Shows a confirmation dialog . The action continues in { @link # onConfirmation ( String ) } , { @link # onNeutral ( String ) } or { @link # onCancel ( String ) } ,
* depending upon the user selection in the dialog .
* /
private void removeFile ( ) {
ConfirmationDialogFragment confDialog = ConfirmationDialogFragment . newInstance (
R . string . confirmation_remove_alert ,
2013-05-30 19:53:21 +04:00
new String [ ] { getFile ( ) . getFileName ( ) } ,
2013-02-18 14:23:18 +04:00
R . string . confirmation_remove_remote_and_local ,
R . string . confirmation_remove_local ,
R . string . common_cancel ) ;
confDialog . setOnConfirmationListener ( this ) ;
confDialog . show ( getFragmentManager ( ) , ConfirmationDialogFragment . FTAG_CONFIRMATION ) ;
2013-02-14 22:21:09 +04:00
}
2013-02-18 14:23:18 +04:00
/ * *
* Performs the removal of the previewed file , both locally and in the server .
* /
2013-02-14 22:21:09 +04:00
@Override
public void onConfirmation ( String callerTag ) {
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
if ( mStorageManager . getFileById ( file . getFileId ( ) ) ! = null ) { // check that the file is still there;
2013-02-18 14:23:18 +04:00
stopPreview ( true ) ;
2013-05-30 19:53:21 +04:00
mLastRemoteOperation = new RemoveFileOperation ( file , // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
2013-02-18 14:23:18 +04:00
true ,
mStorageManager ) ;
2013-04-25 21:39:22 +04:00
mLastRemoteOperation . execute ( mAccount , getSherlockActivity ( ) , this , mHandler , getSherlockActivity ( ) ) ;
2013-02-18 14:23:18 +04:00
2013-05-30 19:53:21 +04:00
getActivity ( ) . showDialog ( FileDisplayActivity . DIALOG_SHORT_WAIT ) ;
2013-02-14 22:21:09 +04:00
}
}
2013-02-18 14:23:18 +04:00
/ * *
* Removes the file from local storage
* /
2013-02-14 22:21:09 +04:00
@Override
public void onNeutral ( String callerTag ) {
2013-02-18 14:23:18 +04:00
// TODO this code should be made in a secondary thread,
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
if ( file . isDown ( ) ) { // checks it is still there
2013-02-18 14:23:18 +04:00
stopPreview ( true ) ;
2013-05-30 19:53:21 +04:00
File f = new File ( file . getStoragePath ( ) ) ;
2013-02-14 22:21:09 +04:00
f . delete ( ) ;
2013-05-30 19:53:21 +04:00
file . setStoragePath ( null ) ;
mStorageManager . saveFile ( file ) ;
2013-02-18 14:23:18 +04:00
finish ( ) ;
2013-02-14 22:21:09 +04:00
}
}
2013-02-18 14:23:18 +04:00
/ * *
* User cancelled the removal action .
* /
2013-02-14 22:21:09 +04:00
@Override
public void onCancel ( String callerTag ) {
2013-02-18 14:23:18 +04:00
// nothing to do here
2013-02-14 22:21:09 +04:00
}
2013-02-18 14:23:18 +04:00
2013-02-14 22:21:09 +04:00
/ * *
2013-02-26 22:04:42 +04:00
* Helper method to test if an { @link OCFile } can be passed to a { @link PreviewMediaFragment } to be previewed .
2013-02-14 22:21:09 +04:00
*
* @param file File to test if can be previewed .
* @return ' True ' if the file can be handled by the fragment .
* /
public static boolean canBePreviewed ( OCFile file ) {
2013-02-26 22:04:42 +04:00
return ( file ! = null & & ( file . isAudio ( ) | | file . isVideo ( ) ) ) ;
2013-02-14 22:21:09 +04:00
}
2013-02-18 14:23:18 +04:00
/ * *
2013-02-14 22:21:09 +04:00
* { @inheritDoc }
2013-02-18 14:23:18 +04:00
* /
2013-02-14 22:21:09 +04:00
@Override
public void onRemoteOperationFinish ( RemoteOperation operation , RemoteOperationResult result ) {
if ( operation . equals ( mLastRemoteOperation ) ) {
if ( operation instanceof RemoveFileOperation ) {
onRemoveFileOperationFinish ( ( RemoveFileOperation ) operation , result ) ;
}
}
}
private void onRemoveFileOperationFinish ( RemoveFileOperation operation , RemoteOperationResult result ) {
2013-05-30 19:53:21 +04:00
getActivity ( ) . dismissDialog ( FileDisplayActivity . DIALOG_SHORT_WAIT ) ;
2013-02-14 22:21:09 +04:00
if ( result . isSuccess ( ) ) {
Toast msg = Toast . makeText ( getActivity ( ) . getApplicationContext ( ) , R . string . remove_success_msg , Toast . LENGTH_LONG ) ;
msg . show ( ) ;
2013-02-18 14:23:18 +04:00
finish ( ) ;
2013-02-14 22:21:09 +04:00
} else {
Toast msg = Toast . makeText ( getActivity ( ) , R . string . remove_fail_msg , Toast . LENGTH_LONG ) ;
msg . show ( ) ;
if ( result . isSslRecoverableException ( ) ) {
// TODO show the SSL warning dialog
}
}
}
2013-02-18 14:23:18 +04:00
private void stopPreview ( boolean stopAudio ) {
2013-05-30 19:53:21 +04:00
OCFile file = getFile ( ) ;
if ( file . isAudio ( ) & & stopAudio ) {
2013-02-18 14:23:18 +04:00
mMediaServiceBinder . pause ( ) ;
2013-05-30 19:53:21 +04:00
} else if ( file . isVideo ( ) ) {
2013-02-18 14:23:18 +04:00
mVideoPreview . stopPlayback ( ) ;
}
}
/ * *
* Finishes the preview
* /
private void finish ( ) {
2013-05-30 19:53:21 +04:00
getActivity ( ) . onBackPressed ( ) ;
2013-02-18 14:23:18 +04:00
}
2013-04-26 16:02:17 +04:00
public int getPosition ( ) {
2013-04-30 15:16:08 +04:00
if ( mPrepared ) {
mSavedPlaybackPosition = mVideoPreview . getCurrentPosition ( ) ;
}
Log_OC . e ( TAG , " getting position: " + mSavedPlaybackPosition ) ;
2013-04-26 16:02:17 +04:00
return mSavedPlaybackPosition ;
}
public boolean isPlaying ( ) {
2013-04-30 15:16:08 +04:00
if ( mPrepared ) {
mAutoplay = mVideoPreview . isPlaying ( ) ;
}
2013-04-26 16:02:17 +04:00
return mAutoplay ;
}
2013-02-14 22:21:09 +04:00
}