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/>. 
  17 package com
.owncloud
.android
.ui
.preview
; 
  19 import java
.util
.ArrayList
; 
  20 import java
.util
.List
; 
  22 import android
.accounts
.Account
; 
  23 import android
.app
.Activity
; 
  24 import android
.app
.AlertDialog
; 
  25 import android
.content
.ActivityNotFoundException
; 
  26 import android
.content
.ComponentName
; 
  27 import android
.content
.Context
; 
  28 import android
.content
.DialogInterface
; 
  29 import android
.content
.Intent
; 
  30 import android
.content
.ServiceConnection
; 
  31 import android
.content
.res
.Configuration
; 
  32 import android
.media
.MediaPlayer
; 
  33 import android
.media
.MediaPlayer
.OnCompletionListener
; 
  34 import android
.media
.MediaPlayer
.OnErrorListener
; 
  35 import android
.media
.MediaPlayer
.OnPreparedListener
; 
  36 import android
.net
.Uri
; 
  37 import android
.os
.Build
; 
  38 import android
.os
.Bundle
; 
  39 import android
.os
.Handler
; 
  40 import android
.os
.IBinder
; 
  41 import android
.view
.LayoutInflater
; 
  42 import android
.view
.MotionEvent
; 
  43 import android
.view
.View
; 
  44 import android
.view
.View
.OnTouchListener
; 
  45 import android
.view
.ViewGroup
; 
  46 import android
.webkit
.MimeTypeMap
; 
  47 import android
.widget
.ImageView
; 
  48 import android
.widget
.Toast
; 
  49 import android
.widget
.VideoView
; 
  51 import com
.actionbarsherlock
.view
.Menu
; 
  52 import com
.actionbarsherlock
.view
.MenuInflater
; 
  53 import com
.actionbarsherlock
.view
.MenuItem
; 
  54 import com
.owncloud
.android
.R
; 
  55 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
; 
  56 import com
.owncloud
.android
.datamodel
.OCFile
; 
  57 import com
.owncloud
.android
.media
.MediaControlView
; 
  58 import com
.owncloud
.android
.media
.MediaService
; 
  59 import com
.owncloud
.android
.media
.MediaServiceBinder
; 
  60 import com
.owncloud
.android
.lib
.network
.webdav
.WebdavUtils
; 
  61 import com
.owncloud
.android
.lib
.operations
.common
.OnRemoteOperationListener
; 
  62 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperation
; 
  63 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperationResult
; 
  64 import com
.owncloud
.android
.operations
.RemoveFileOperation
; 
  65 import com
.owncloud
.android
.ui
.activity
.FileActivity
; 
  66 import com
.owncloud
.android
.ui
.activity
.FileDisplayActivity
; 
  67 import com
.owncloud
.android
.ui
.fragment
.ConfirmationDialogFragment
; 
  68 import com
.owncloud
.android
.ui
.fragment
.FileFragment
; 
  69 import com
.owncloud
.android
.utils
.Log_OC
; 
  73  * This fragment shows a preview of a downloaded media file (audio or video). 
  75  * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}. 
  77  * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too. 
  79  * @author David A. Velasco 
  81 public class PreviewMediaFragment 
extends FileFragment 
implements 
  83         ConfirmationDialogFragment
.ConfirmationDialogFragmentListener
, OnRemoteOperationListener  
{ 
  85     public static final String EXTRA_FILE 
= "FILE"; 
  86     public static final String EXTRA_ACCOUNT 
= "ACCOUNT"; 
  87     private static final String EXTRA_PLAY_POSITION 
= "PLAY_POSITION"; 
  88     private static final String EXTRA_PLAYING 
= "PLAYING"; 
  91     private Account mAccount
; 
  92     private FileDataStorageManager mStorageManager
; 
  93     private ImageView mImagePreview
; 
  94     private VideoView mVideoPreview
; 
  95     private int mSavedPlaybackPosition
; 
  97     private Handler mHandler
; 
  98     private RemoteOperation mLastRemoteOperation
; 
 100     private MediaServiceBinder mMediaServiceBinder 
= null
; 
 101     private MediaControlView mMediaController 
= null
; 
 102     private MediaServiceConnection mMediaServiceConnection 
= null
; 
 103     private VideoHelper mVideoHelper
; 
 104     private boolean mAutoplay
; 
 105     public boolean mPrepared
; 
 107     private static final String TAG 
= PreviewMediaFragment
.class.getSimpleName(); 
 111      * Creates a fragment to preview a file. 
 113      * When 'fileToDetail' or 'ocAccount' are null 
 115      * @param fileToDetail      An {@link OCFile} to preview in the fragment 
 116      * @param ocAccount         An ownCloud account; needed to start downloads 
 118     public PreviewMediaFragment(OCFile fileToDetail
, Account ocAccount
, int startPlaybackPosition
, boolean autoplay
) { 
 120         mAccount 
= ocAccount
; 
 121         mSavedPlaybackPosition 
= startPlaybackPosition
; 
 122         mStorageManager 
= null
; // we need a context to init this; the container activity is not available yet at this moment  
 123         mAutoplay 
= autoplay
; 
 128      *  Creates an empty fragment for previews. 
 130      *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside). 
 132      *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction  
 134     public PreviewMediaFragment() { 
 137         mSavedPlaybackPosition 
= 0; 
 138         mStorageManager 
= null
; 
 147     public void onCreate(Bundle savedInstanceState
) { 
 148         super.onCreate(savedInstanceState
); 
 149         mHandler 
= new Handler(); 
 150         setHasOptionsMenu(true
); 
 158     public View 
onCreateView(LayoutInflater inflater
, ViewGroup container
, 
 159             Bundle savedInstanceState
) { 
 160         super.onCreateView(inflater
, container
, savedInstanceState
); 
 161         Log_OC
.e(TAG
, "onCreateView"); 
 164         mView 
= inflater
.inflate(R
.layout
.file_preview
, container
, false
); 
 166         mImagePreview 
= (ImageView
)mView
.findViewById(R
.id
.image_preview
); 
 167         mVideoPreview 
= (VideoView
)mView
.findViewById(R
.id
.video_preview
); 
 168         mVideoPreview
.setOnTouchListener(this); 
 170         mMediaController 
= (MediaControlView
)mView
.findViewById(R
.id
.media_controller
); 
 180     public void onAttach(Activity activity
) { 
 181         super.onAttach(activity
); 
 182         Log_OC
.e(TAG
, "onAttach"); 
 184         if (!(activity 
instanceof FileFragment
.ContainerActivity
)) 
 185             throw new ClassCastException(activity
.toString() + " must implement " + FileFragment
.ContainerActivity
.class.getSimpleName()); 
 193     public void onActivityCreated(Bundle savedInstanceState
) { 
 194         super.onActivityCreated(savedInstanceState
); 
 195         Log_OC
.e(TAG
, "onActivityCreated"); 
 197         mStorageManager 
= new FileDataStorageManager(mAccount
, getActivity().getApplicationContext().getContentResolver()); 
 198         if (savedInstanceState 
!= null
) { 
 199             setFile((OCFile
)savedInstanceState
.getParcelable(PreviewMediaFragment
.EXTRA_FILE
)); 
 200             mAccount 
= savedInstanceState
.getParcelable(PreviewMediaFragment
.EXTRA_ACCOUNT
); 
 201             mSavedPlaybackPosition 
= savedInstanceState
.getInt(PreviewMediaFragment
.EXTRA_PLAY_POSITION
); 
 202             mAutoplay 
= savedInstanceState
.getBoolean(PreviewMediaFragment
.EXTRA_PLAYING
); 
 205         OCFile file 
= getFile(); 
 207             throw new IllegalStateException("Instanced with a NULL OCFile"); 
 209         if (mAccount 
== null
) { 
 210             throw new IllegalStateException("Instanced with a NULL ownCloud Account"); 
 212         if (!file
.isDown()) { 
 213             throw new IllegalStateException("There is no local file to preview"); 
 215         if (file
.isVideo()) { 
 216             mVideoPreview
.setVisibility(View
.VISIBLE
); 
 217             mImagePreview
.setVisibility(View
.GONE
); 
 221             mVideoPreview
.setVisibility(View
.GONE
); 
 222             mImagePreview
.setVisibility(View
.VISIBLE
); 
 232     public void onSaveInstanceState(Bundle outState
) { 
 233         super.onSaveInstanceState(outState
); 
 234         Log_OC
.e(TAG
, "onSaveInstanceState"); 
 236         outState
.putParcelable(PreviewMediaFragment
.EXTRA_FILE
, getFile()); 
 237         outState
.putParcelable(PreviewMediaFragment
.EXTRA_ACCOUNT
, mAccount
); 
 239         if (getFile().isVideo()) { 
 240             mSavedPlaybackPosition 
= mVideoPreview
.getCurrentPosition(); 
 241             mAutoplay 
= mVideoPreview
.isPlaying(); 
 242             outState
.putInt(PreviewMediaFragment
.EXTRA_PLAY_POSITION 
, mSavedPlaybackPosition
); 
 243             outState
.putBoolean(PreviewMediaFragment
.EXTRA_PLAYING 
, mAutoplay
); 
 245             outState
.putInt(PreviewMediaFragment
.EXTRA_PLAY_POSITION 
, mMediaServiceBinder
.getCurrentPosition()); 
 246             outState
.putBoolean(PreviewMediaFragment
.EXTRA_PLAYING 
, mMediaServiceBinder
.isPlaying()); 
 252     public void onStart() { 
 254         Log_OC
.e(TAG
, "onStart"); 
 256         OCFile file 
= getFile(); 
 258            if (file
.isAudio()) { 
 261            } else if (file
.isVideo()) { 
 269     private void stopAudio() { 
 270         Intent i 
= new Intent(getSherlockActivity(), MediaService
.class); 
 271         i
.setAction(MediaService
.ACTION_STOP_ALL
); 
 272         getSherlockActivity().startService(i
); 
 280     public void onCreateOptionsMenu(Menu menu
, MenuInflater inflater
) { 
 281         super.onCreateOptionsMenu(menu
, inflater
); 
 283         inflater
.inflate(R
.menu
.file_actions_menu
, menu
); 
 284         List
<Integer
> toHide 
= new ArrayList
<Integer
>();     
 286         MenuItem item 
= null
; 
 287         toHide
.add(R
.id
.action_cancel_download
); 
 288         toHide
.add(R
.id
.action_cancel_upload
); 
 289         toHide
.add(R
.id
.action_download_file
); 
 290         toHide
.add(R
.id
.action_sync_file
); 
 291         toHide
.add(R
.id
.action_rename_file
);    // by now 
 294         if (!getFile().isShareByLink()) { 
 295             toHide
.add(R
.id
.action_unshare_file
); 
 298         for (int i 
: toHide
) { 
 299             item 
= menu
.findItem(i
); 
 301                 item
.setVisible(false
); 
 302                 item
.setEnabled(false
); 
 313     public void onPrepareOptionsMenu(Menu menu
) { 
 314         super.onPrepareOptionsMenu(menu
); 
 317         if (!getFile().isShareByLink()) { 
 318             MenuItem item 
= menu
.findItem(R
.id
.action_unshare_file
); 
 319             item
.setVisible(false
); 
 320             item
.setEnabled(false
); 
 329     public boolean onOptionsItemSelected(MenuItem item
) { 
 330         switch (item
.getItemId()) { 
 331             case R
.id
.action_share_file
: { 
 335             case R
.id
.action_unshare_file
: { 
 336                 unshareFileWithLink(); 
 339             case R
.id
.action_open_file_with
: { 
 343             case R
.id
.action_remove_file
: { 
 347             case R
.id
.action_see_details
: { 
 359     private void unshareFileWithLink() { 
 361         FileActivity activity 
= (FileActivity
)((FileFragment
.ContainerActivity
)getActivity()); 
 362         activity
.getFileOperationsHelper().unshareFileWithLink(getFile(), activity
); 
 365     private void shareFileWithLink() { 
 367         FileActivity activity 
= (FileActivity
)((FileFragment
.ContainerActivity
)getActivity()); 
 368         activity
.getFileOperationsHelper().shareFileWithLink(getFile(), activity
); 
 373     private void seeDetails() { 
 375         ((FileFragment
.ContainerActivity
)getActivity()).showDetails(getFile());         
 379     private void prepareVideo() { 
 380         // create helper to get more control on the playback 
 381         mVideoHelper 
= new VideoHelper(); 
 382         mVideoPreview
.setOnPreparedListener(mVideoHelper
); 
 383         mVideoPreview
.setOnCompletionListener(mVideoHelper
); 
 384         mVideoPreview
.setOnErrorListener(mVideoHelper
); 
 387     private void playVideo() { 
 388         // create and prepare control panel for the user 
 389         mMediaController
.setMediaPlayer(mVideoPreview
); 
 391         // load the video file in the video player ; when done, VideoHelper#onPrepared() will be called 
 392         mVideoPreview
.setVideoPath(getFile().getStoragePath());  
 396     private class VideoHelper 
implements OnCompletionListener
, OnPreparedListener
, OnErrorListener 
{ 
 399          * Called when the file is ready to be played. 
 401          * Just starts the playback. 
 403          * @param   mp    {@link MediaPlayer} instance performing the playback. 
 406         public void onPrepared(MediaPlayer vp
) { 
 407             Log_OC
.e(TAG
, "onPrepared"); 
 408             mVideoPreview
.seekTo(mSavedPlaybackPosition
); 
 410                 mVideoPreview
.start(); 
 412             mMediaController
.setEnabled(true
); 
 413             mMediaController
.updatePausePlay(); 
 419          * Called when the file is finished playing. 
 421          * Finishes the activity. 
 423          * @param   mp    {@link MediaPlayer} instance performing the playback. 
 426         public void onCompletion(MediaPlayer  mp
) { 
 427             Log_OC
.e(TAG
, "completed"); 
 429                 mVideoPreview
.seekTo(0); 
 430                 // next lines are necessary to work around undesired video loops 
 431                 if (Build
.VERSION
.SDK_INT 
== Build
.VERSION_CODES
.GINGERBREAD
) { 
 432                     mVideoPreview
.pause();    
 434                 } else if (Build
.VERSION
.SDK_INT 
== Build
.VERSION_CODES
.GINGERBREAD_MR1
) { 
 435                     // mVideePreview.pause() is not enough 
 437                     mMediaController
.setEnabled(false
); 
 438                     mVideoPreview
.stopPlayback(); 
 440                     mSavedPlaybackPosition 
= 0; 
 441                     mVideoPreview
.setVideoPath(getFile().getStoragePath()); 
 443             } // else : called from onError() 
 444             mMediaController
.updatePausePlay(); 
 449          * Called when an error in playback occurs. 
 451          * @param   mp      {@link MediaPlayer} instance performing the playback. 
 452          * @param   what    Type of error 
 453          * @param   extra   Extra code specific to the error 
 456         public boolean onError(MediaPlayer mp
, int what
, int extra
) { 
 457             if (mVideoPreview
.getWindowToken() != null
) { 
 458                 String message 
= MediaService
.getMessageForMediaError(getActivity(), what
, extra
); 
 459                 new AlertDialog
.Builder(getActivity()) 
 461                         .setPositiveButton(android
.R
.string
.VideoView_error_button
, 
 462                                 new DialogInterface
.OnClickListener() { 
 463                                     public void onClick(DialogInterface dialog
, int whichButton
) { 
 465                                         VideoHelper
.this.onCompletion(null
); 
 468                         .setCancelable(false
) 
 478     public void onPause() { 
 480         Log_OC
.e(TAG
, "onPause"); 
 484     public void onResume() { 
 486         Log_OC
.e(TAG
, "onResume"); 
 490     public void onDestroy() { 
 492         Log_OC
.e(TAG
, "onDestroy"); 
 496     public void onStop() { 
 497         Log_OC
.e(TAG
, "onStop"); 
 501         if (mMediaServiceConnection 
!= null
) { 
 502             Log_OC
.d(TAG
, "Unbinding from MediaService ..."); 
 503             if (mMediaServiceBinder 
!= null 
&& mMediaController 
!= null
) { 
 504                 mMediaServiceBinder
.unregisterMediaController(mMediaController
); 
 506             getActivity().unbindService(mMediaServiceConnection
); 
 507             mMediaServiceConnection 
= null
; 
 508             mMediaServiceBinder 
= null
; 
 513     public boolean onTouch(View v
, MotionEvent event
) { 
 514         if (event
.getAction() == MotionEvent
.ACTION_DOWN 
&& v 
== mVideoPreview
) { 
 515             startFullScreenVideo(); 
 522     private void startFullScreenVideo() { 
 523         Intent i 
= new Intent(getActivity(), PreviewVideoActivity
.class); 
 524         i
.putExtra(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 525         i
.putExtra(FileActivity
.EXTRA_FILE
, getFile()); 
 526         i
.putExtra(PreviewVideoActivity
.EXTRA_AUTOPLAY
, mVideoPreview
.isPlaying()); 
 527         mVideoPreview
.pause(); 
 528         i
.putExtra(PreviewVideoActivity
.EXTRA_START_POSITION
, mVideoPreview
.getCurrentPosition()); 
 529         startActivityForResult(i
, 0); 
 533     public void onConfigurationChanged (Configuration newConfig
) { 
 534         Log_OC
.e(TAG
, "onConfigurationChanged " + this); 
 538     public void onActivityResult (int requestCode
, int resultCode
, Intent data
) { 
 539         Log_OC
.e(TAG
, "onActivityResult " + this); 
 540         super.onActivityResult(requestCode
, resultCode
, data
); 
 541         if (resultCode 
== Activity
.RESULT_OK
) { 
 542             mSavedPlaybackPosition 
= data
.getExtras().getInt(PreviewVideoActivity
.EXTRA_START_POSITION
); 
 543             mAutoplay 
= data
.getExtras().getBoolean(PreviewVideoActivity
.EXTRA_AUTOPLAY
);  
 548     private void playAudio() { 
 549         OCFile file 
= getFile(); 
 550         if (!mMediaServiceBinder
.isPlaying(file
)) { 
 551             Log_OC
.d(TAG
, "starting playback of " + file
.getStoragePath()); 
 552             mMediaServiceBinder
.start(mAccount
, file
, mAutoplay
, mSavedPlaybackPosition
); 
 555             if (!mMediaServiceBinder
.isPlaying() && mAutoplay
) { 
 556                 mMediaServiceBinder
.start(); 
 557                 mMediaController
.updatePausePlay(); 
 563     private void bindMediaService() { 
 564         Log_OC
.d(TAG
, "Binding to MediaService..."); 
 565         if (mMediaServiceConnection 
== null
) { 
 566             mMediaServiceConnection 
= new MediaServiceConnection(); 
 568         getActivity().bindService(  new Intent(getActivity(),  
 570                                     mMediaServiceConnection
,  
 571                                     Context
.BIND_AUTO_CREATE
); 
 572             // follow the flow in MediaServiceConnection#onServiceConnected(...) 
 575     /** Defines callbacks for service binding, passed to bindService() */ 
 576     private class MediaServiceConnection 
implements ServiceConnection 
{ 
 579         public void onServiceConnected(ComponentName component
, IBinder service
) { 
 580             if (component
.equals(new ComponentName(getActivity(), MediaService
.class))) { 
 581                 Log_OC
.d(TAG
, "Media service connected"); 
 582                 mMediaServiceBinder 
= (MediaServiceBinder
) service
; 
 583                 if (mMediaServiceBinder 
!= null
) { 
 584                     prepareMediaController(); 
 585                     playAudio();    // do not wait for the touch of nobody to play audio 
 587                     Log_OC
.d(TAG
, "Successfully bound to MediaService, MediaController ready"); 
 590                     Log_OC
.e(TAG
, "Unexpected response from MediaService while binding"); 
 595         private void prepareMediaController() { 
 596             mMediaServiceBinder
.registerMediaController(mMediaController
); 
 597             if (mMediaController 
!= null
) { 
 598                 mMediaController
.setMediaPlayer(mMediaServiceBinder
); 
 599                 mMediaController
.setEnabled(true
); 
 600                 mMediaController
.updatePausePlay(); 
 605         public void onServiceDisconnected(ComponentName component
) { 
 606             if (component
.equals(new ComponentName(getActivity(), MediaService
.class))) { 
 607                 Log_OC
.e(TAG
, "Media service suddenly disconnected"); 
 608                 if (mMediaController 
!= null
) { 
 609                     mMediaController
.setMediaPlayer(null
); 
 611                     Toast
.makeText(getActivity(), "No media controller to release when disconnected from media service", Toast
.LENGTH_SHORT
).show(); 
 613                 mMediaServiceBinder 
= null
; 
 614                 mMediaServiceConnection 
= null
; 
 622      * Opens the previewed file with an external application. 
 624      * TODO - improve this; instead of prioritize the actions available for the MIME type in the server,  
 625      * we should get a list of available apps for MIME tpye in the server and join it with the list of  
 626      * available apps for the MIME type known from the file extension, to let the user choose 
 628     private void openFile() { 
 629         OCFile file 
= getFile(); 
 631         String storagePath 
= file
.getStoragePath(); 
 632         String encodedStoragePath 
= WebdavUtils
.encodePath(storagePath
); 
 634             Intent i 
= new Intent(Intent
.ACTION_VIEW
); 
 635             i
.setDataAndType(Uri
.parse("file://"+ encodedStoragePath
), file
.getMimetype()); 
 636             i
.setFlags(Intent
.FLAG_GRANT_READ_URI_PERMISSION 
| Intent
.FLAG_GRANT_WRITE_URI_PERMISSION
); 
 639         } catch (Throwable t
) { 
 640             Log_OC
.e(TAG
, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file
.getMimetype()); 
 641             boolean toastIt 
= true
;  
 642             String mimeType 
= ""; 
 644                 Intent i 
= new Intent(Intent
.ACTION_VIEW
); 
 645                 mimeType 
= MimeTypeMap
.getSingleton().getMimeTypeFromExtension(storagePath
.substring(storagePath
.lastIndexOf('.') + 1)); 
 646                 if (mimeType 
== null 
|| !mimeType
.equals(file
.getMimetype())) { 
 647                     if (mimeType 
!= null
) { 
 648                         i
.setDataAndType(Uri
.parse("file://"+ encodedStoragePath
), mimeType
); 
 651                         i
.setDataAndType(Uri
.parse("file://"+ encodedStoragePath
), "*-/*"); 
 653                     i
.setFlags(Intent
.FLAG_GRANT_READ_URI_PERMISSION 
| Intent
.FLAG_GRANT_WRITE_URI_PERMISSION
); 
 658             } catch (IndexOutOfBoundsException e
) { 
 659                 Log_OC
.e(TAG
, "Trying to find out MIME type of a file without extension: " + storagePath
); 
 661             } catch (ActivityNotFoundException e
) { 
 662                 Log_OC
.e(TAG
, "No activity found to handle: " + storagePath 
+ " with MIME type " + mimeType 
+ " obtained from extension"); 
 664             } catch (Throwable th
) { 
 665                 Log_OC
.e(TAG
, "Unexpected problem when opening: " + storagePath
, th
); 
 669                     Toast
.makeText(getActivity(), "There is no application to handle file " + file
.getFileName(), Toast
.LENGTH_SHORT
).show(); 
 678      * Starts a the removal of the previewed file. 
 680      * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)}, 
 681      * depending upon the user selection in the dialog.  
 683     private void removeFile() { 
 684         ConfirmationDialogFragment confDialog 
= ConfirmationDialogFragment
.newInstance( 
 685                 R
.string
.confirmation_remove_alert
, 
 686                 new String
[]{getFile().getFileName()}, 
 687                 R
.string
.confirmation_remove_remote_and_local
, 
 688                 R
.string
.confirmation_remove_local
, 
 689                 R
.string
.common_cancel
); 
 690         confDialog
.setOnConfirmationListener(this); 
 691         confDialog
.show(getFragmentManager(), ConfirmationDialogFragment
.FTAG_CONFIRMATION
); 
 696      * Performs the removal of the previewed file, both locally and in the server. 
 699     public void onConfirmation(String callerTag
) { 
 700         OCFile file 
= getFile(); 
 701         if (mStorageManager
.getFileById(file
.getFileId()) != null
) {   // check that the file is still there; 
 703             mLastRemoteOperation 
= new RemoveFileOperation( file
,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters 
 706             mLastRemoteOperation
.execute(mAccount
, getSherlockActivity(), this, mHandler
, getSherlockActivity()); 
 708             ((FileDisplayActivity
) getActivity()).showLoadingDialog(); 
 714      * Removes the file from local storage 
 717     public void onNeutral(String callerTag
) { 
 718         OCFile file 
= getFile(); 
 720         mStorageManager
.removeFile(file
, false
, true
);    // TODO perform in background task / new thread 
 725      * User cancelled the removal action. 
 728     public void onCancel(String callerTag
) { 
 729         // nothing to do here 
 734      * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment} to be previewed. 
 736      * @param file      File to test if can be previewed. 
 737      * @return          'True' if the file can be handled by the fragment. 
 739     public static boolean canBePreviewed(OCFile file
) { 
 740         return (file 
!= null 
&& (file
.isAudio() || file
.isVideo())); 
 747     public void onRemoteOperationFinish(RemoteOperation operation
, RemoteOperationResult result
) { 
 748         if (operation
.equals(mLastRemoteOperation
)) { 
 749             if (operation 
instanceof RemoveFileOperation
) { 
 750                 onRemoveFileOperationFinish((RemoveFileOperation
)operation
, result
); 
 755     private void onRemoveFileOperationFinish(RemoveFileOperation operation
, RemoteOperationResult result
) { 
 756         ((FileDisplayActivity
) getActivity()).dismissLoadingDialog(); 
 757         if (result
.isSuccess()) { 
 758             Toast msg 
= Toast
.makeText(getActivity().getApplicationContext(), R
.string
.remove_success_msg
, Toast
.LENGTH_LONG
); 
 763             Toast msg 
= Toast
.makeText(getActivity(), R
.string
.remove_fail_msg
, Toast
.LENGTH_LONG
);  
 765             if (result
.isSslRecoverableException()) { 
 766                 // TODO show the SSL warning dialog 
 771     private void stopPreview(boolean stopAudio
) { 
 772         OCFile file 
= getFile(); 
 773         if (file
.isAudio() && stopAudio
) { 
 774             mMediaServiceBinder
.pause(); 
 776         } else if (file
.isVideo()) { 
 777             mVideoPreview
.stopPlayback(); 
 784      * Finishes the preview 
 786     private void finish() { 
 787         getActivity().onBackPressed(); 
 791     public int getPosition() { 
 793             mSavedPlaybackPosition 
= mVideoPreview
.getCurrentPosition(); 
 795         Log_OC
.e(TAG
, "getting position: " + mSavedPlaybackPosition
); 
 796         return mSavedPlaybackPosition
; 
 799     public boolean isPlaying() { 
 801             mAutoplay 
= mVideoPreview
.isPlaying();