Refactoring to reduce dependencies and duplicated code (WIP)
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / preview / PreviewMediaFragment.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012-2013 ownCloud Inc.
3 *
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.
7 *
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.
12 *
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/>.
15 *
16 */
17 package com.owncloud.android.ui.preview;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
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;
50
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.common.network.WebdavUtils;
61 import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
62 import com.owncloud.android.lib.common.operations.RemoteOperation;
63 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
64 import com.owncloud.android.operations.RemoveFileOperation;
65 import com.owncloud.android.ui.activity.FileActivity;
66 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
67 import com.owncloud.android.ui.fragment.FileFragment;
68 import com.owncloud.android.utils.Log_OC;
69
70
71 /**
72 * This fragment shows a preview of a downloaded media file (audio or video).
73 *
74 * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
75 *
76 * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
77 *
78 * @author David A. Velasco
79 */
80 public class PreviewMediaFragment extends FileFragment implements
81 OnTouchListener,
82 ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener {
83
84 public static final String EXTRA_FILE = "FILE";
85 public static final String EXTRA_ACCOUNT = "ACCOUNT";
86 private static final String EXTRA_PLAY_POSITION = "PLAY_POSITION";
87 private static final String EXTRA_PLAYING = "PLAYING";
88
89 private View mView;
90 private Account mAccount;
91 private ImageView mImagePreview;
92 private VideoView mVideoPreview;
93 private int mSavedPlaybackPosition;
94
95 private Handler mHandler;
96 private RemoteOperation mLastRemoteOperation;
97
98 private MediaServiceBinder mMediaServiceBinder = null;
99 private MediaControlView mMediaController = null;
100 private MediaServiceConnection mMediaServiceConnection = null;
101 private VideoHelper mVideoHelper;
102 private boolean mAutoplay;
103 public boolean mPrepared;
104
105 private static final String TAG = PreviewMediaFragment.class.getSimpleName();
106
107
108 /**
109 * Creates a fragment to preview a file.
110 *
111 * When 'fileToDetail' or 'ocAccount' are null
112 *
113 * @param fileToDetail An {@link OCFile} to preview in the fragment
114 * @param ocAccount An ownCloud account; needed to start downloads
115 */
116 public PreviewMediaFragment(OCFile fileToDetail, Account ocAccount, int startPlaybackPosition, boolean autoplay) {
117 super(fileToDetail);
118 mAccount = ocAccount;
119 mSavedPlaybackPosition = startPlaybackPosition;
120 mAutoplay = autoplay;
121 }
122
123
124 /**
125 * Creates an empty fragment for previews.
126 *
127 * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
128 *
129 * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction
130 */
131 public PreviewMediaFragment() {
132 super();
133 mAccount = null;
134 mSavedPlaybackPosition = 0;
135 mAutoplay = true;
136 }
137
138
139 /**
140 * {@inheritDoc}
141 */
142 @Override
143 public void onCreate(Bundle savedInstanceState) {
144 super.onCreate(savedInstanceState);
145 mHandler = new Handler();
146 setHasOptionsMenu(true);
147 }
148
149
150 /**
151 * {@inheritDoc}
152 */
153 @Override
154 public View onCreateView(LayoutInflater inflater, ViewGroup container,
155 Bundle savedInstanceState) {
156 super.onCreateView(inflater, container, savedInstanceState);
157 Log_OC.e(TAG, "onCreateView");
158
159
160 mView = inflater.inflate(R.layout.file_preview, container, false);
161
162 mImagePreview = (ImageView)mView.findViewById(R.id.image_preview);
163 mVideoPreview = (VideoView)mView.findViewById(R.id.video_preview);
164 mVideoPreview.setOnTouchListener(this);
165
166 mMediaController = (MediaControlView)mView.findViewById(R.id.media_controller);
167
168 return mView;
169 }
170
171
172 /**
173 * {@inheritDoc}
174 */
175 @Override
176 public void onAttach(Activity activity) {
177 super.onAttach(activity);
178 Log_OC.e(TAG, "onAttach");
179
180 if (!(activity instanceof FileFragment.ContainerActivity))
181 throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
182 }
183
184
185 /**
186 * {@inheritDoc}
187 */
188 @Override
189 public void onActivityCreated(Bundle savedInstanceState) {
190 super.onActivityCreated(savedInstanceState);
191 Log_OC.e(TAG, "onActivityCreated");
192
193 if (savedInstanceState != null) {
194 setFile((OCFile)savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE));
195 mAccount = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_ACCOUNT);
196 mSavedPlaybackPosition = savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
197 mAutoplay = savedInstanceState.getBoolean(PreviewMediaFragment.EXTRA_PLAYING);
198
199 }
200 OCFile file = getFile();
201 if (file == null) {
202 throw new IllegalStateException("Instanced with a NULL OCFile");
203 }
204 if (mAccount == null) {
205 throw new IllegalStateException("Instanced with a NULL ownCloud Account");
206 }
207 if (!file.isDown()) {
208 throw new IllegalStateException("There is no local file to preview");
209 }
210 if (file.isVideo()) {
211 mVideoPreview.setVisibility(View.VISIBLE);
212 mImagePreview.setVisibility(View.GONE);
213 prepareVideo();
214
215 } else {
216 mVideoPreview.setVisibility(View.GONE);
217 mImagePreview.setVisibility(View.VISIBLE);
218 }
219
220 }
221
222
223 /**
224 * {@inheritDoc}
225 */
226 @Override
227 public void onSaveInstanceState(Bundle outState) {
228 super.onSaveInstanceState(outState);
229 Log_OC.e(TAG, "onSaveInstanceState");
230
231 outState.putParcelable(PreviewMediaFragment.EXTRA_FILE, getFile());
232 outState.putParcelable(PreviewMediaFragment.EXTRA_ACCOUNT, mAccount);
233
234 if (getFile().isVideo()) {
235 mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
236 mAutoplay = mVideoPreview.isPlaying();
237 outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mSavedPlaybackPosition);
238 outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mAutoplay);
239 } else {
240 outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mMediaServiceBinder.getCurrentPosition());
241 outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mMediaServiceBinder.isPlaying());
242 }
243 }
244
245
246 @Override
247 public void onStart() {
248 super.onStart();
249 Log_OC.e(TAG, "onStart");
250
251 OCFile file = getFile();
252 if (file != null) {
253 if (file.isAudio()) {
254 bindMediaService();
255
256 } else if (file.isVideo()) {
257 stopAudio();
258 playVideo();
259 }
260 }
261 }
262
263
264 private void stopAudio() {
265 Intent i = new Intent(getSherlockActivity(), MediaService.class);
266 i.setAction(MediaService.ACTION_STOP_ALL);
267 getSherlockActivity().startService(i);
268 }
269
270
271 /**
272 * {@inheritDoc}
273 */
274 @Override
275 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
276 super.onCreateOptionsMenu(menu, inflater);
277
278 inflater.inflate(R.menu.file_actions_menu, menu);
279 List<Integer> toHide = new ArrayList<Integer>();
280
281 MenuItem item = null;
282 toHide.add(R.id.action_cancel_download);
283 toHide.add(R.id.action_cancel_upload);
284 toHide.add(R.id.action_download_file);
285 toHide.add(R.id.action_sync_file);
286 toHide.add(R.id.action_rename_file); // by now
287
288 // Options shareLink
289 if (!getFile().isShareByLink()) {
290 toHide.add(R.id.action_unshare_file);
291 }
292
293 // Send file
294 boolean sendEnabled = getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on");
295 if (!sendEnabled) {
296 toHide.add(R.id.action_send_file);
297 }
298
299 for (int i : toHide) {
300 item = menu.findItem(i);
301 if (item != null) {
302 item.setVisible(false);
303 item.setEnabled(false);
304 }
305 }
306
307 }
308
309
310 /**
311 * {@inheritDoc}
312 */
313 @Override
314 public void onPrepareOptionsMenu(Menu menu) {
315 super.onPrepareOptionsMenu(menu);
316
317 MenuItem item = menu.findItem(R.id.action_unshare_file);
318 // Options shareLink
319 if (!getFile().isShareByLink()) {
320 item.setVisible(false);
321 item.setEnabled(false);
322 } else {
323 item.setVisible(true);
324 item.setEnabled(true);
325 }
326 }
327
328
329 /**
330 * {@inheritDoc}
331 */
332 @Override
333 public boolean onOptionsItemSelected(MenuItem item) {
334 switch (item.getItemId()) {
335 case R.id.action_share_file: {
336 shareFileWithLink();
337 return true;
338 }
339 case R.id.action_unshare_file: {
340 unshareFileWithLink();
341 return true;
342 }
343 case R.id.action_open_file_with: {
344 openFile();
345 return true;
346 }
347 case R.id.action_remove_file: {
348 removeFile();
349 return true;
350 }
351 case R.id.action_see_details: {
352 seeDetails();
353 return true;
354 }
355 case R.id.action_send_file: {
356 sendFile();
357 }
358
359 default:
360 return false;
361 }
362 }
363
364
365
366 /**
367 * Update the file of the fragment with file value
368 * @param file
369 */
370 public void updateFile(OCFile file){
371 setFile(file);
372 }
373
374 private void unshareFileWithLink() {
375 stopPreview(false);
376 FileActivity activity = (FileActivity)getSherlockActivity();
377 activity.getFileOperationsHelper().unshareFileWithLink(getFile(), activity);
378 }
379
380 private void shareFileWithLink() {
381 stopPreview(false);
382 FileActivity activity = (FileActivity)getSherlockActivity();
383 activity.getFileOperationsHelper().shareFileWithLink(getFile(), activity);
384
385 }
386
387 private void sendFile() {
388 stopPreview(false);
389 FileActivity activity = (FileActivity)getSherlockActivity();
390 activity.getFileOperationsHelper().sendDownloadedFile(getFile(), activity);
391
392 }
393
394 private void seeDetails() {
395 stopPreview(false);
396 ((FileFragment.ContainerActivity)getSherlockActivity()).showDetails(getFile());
397 }
398
399
400 private void prepareVideo() {
401 // create helper to get more control on the playback
402 mVideoHelper = new VideoHelper();
403 mVideoPreview.setOnPreparedListener(mVideoHelper);
404 mVideoPreview.setOnCompletionListener(mVideoHelper);
405 mVideoPreview.setOnErrorListener(mVideoHelper);
406 }
407
408 private void playVideo() {
409 // create and prepare control panel for the user
410 mMediaController.setMediaPlayer(mVideoPreview);
411
412 // load the video file in the video player ; when done, VideoHelper#onPrepared() will be called
413 mVideoPreview.setVideoPath(getFile().getStoragePath());
414 }
415
416
417 private class VideoHelper implements OnCompletionListener, OnPreparedListener, OnErrorListener {
418
419 /**
420 * Called when the file is ready to be played.
421 *
422 * Just starts the playback.
423 *
424 * @param mp {@link MediaPlayer} instance performing the playback.
425 */
426 @Override
427 public void onPrepared(MediaPlayer vp) {
428 Log_OC.e(TAG, "onPrepared");
429 mVideoPreview.seekTo(mSavedPlaybackPosition);
430 if (mAutoplay) {
431 mVideoPreview.start();
432 }
433 mMediaController.setEnabled(true);
434 mMediaController.updatePausePlay();
435 mPrepared = true;
436 }
437
438
439 /**
440 * Called when the file is finished playing.
441 *
442 * Finishes the activity.
443 *
444 * @param mp {@link MediaPlayer} instance performing the playback.
445 */
446 @Override
447 public void onCompletion(MediaPlayer mp) {
448 Log_OC.e(TAG, "completed");
449 if (mp != null) {
450 mVideoPreview.seekTo(0);
451 // next lines are necessary to work around undesired video loops
452 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD) {
453 mVideoPreview.pause();
454
455 } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD_MR1) {
456 // mVideePreview.pause() is not enough
457
458 mMediaController.setEnabled(false);
459 mVideoPreview.stopPlayback();
460 mAutoplay = false;
461 mSavedPlaybackPosition = 0;
462 mVideoPreview.setVideoPath(getFile().getStoragePath());
463 }
464 } // else : called from onError()
465 mMediaController.updatePausePlay();
466 }
467
468
469 /**
470 * Called when an error in playback occurs.
471 *
472 * @param mp {@link MediaPlayer} instance performing the playback.
473 * @param what Type of error
474 * @param extra Extra code specific to the error
475 */
476 @Override
477 public boolean onError(MediaPlayer mp, int what, int extra) {
478 if (mVideoPreview.getWindowToken() != null) {
479 String message = MediaService.getMessageForMediaError(getSherlockActivity(), what, extra);
480 new AlertDialog.Builder(getSherlockActivity())
481 .setMessage(message)
482 .setPositiveButton(android.R.string.VideoView_error_button,
483 new DialogInterface.OnClickListener() {
484 public void onClick(DialogInterface dialog, int whichButton) {
485 dialog.dismiss();
486 VideoHelper.this.onCompletion(null);
487 }
488 })
489 .setCancelable(false)
490 .show();
491 }
492 return true;
493 }
494
495 }
496
497
498 @Override
499 public void onPause() {
500 super.onPause();
501 Log_OC.e(TAG, "onPause");
502 }
503
504 @Override
505 public void onResume() {
506 super.onResume();
507 Log_OC.e(TAG, "onResume");
508 }
509
510 @Override
511 public void onDestroy() {
512 super.onDestroy();
513 Log_OC.e(TAG, "onDestroy");
514 }
515
516 @Override
517 public void onStop() {
518 Log_OC.e(TAG, "onStop");
519 super.onStop();
520
521 mPrepared = false;
522 if (mMediaServiceConnection != null) {
523 Log_OC.d(TAG, "Unbinding from MediaService ...");
524 if (mMediaServiceBinder != null && mMediaController != null) {
525 mMediaServiceBinder.unregisterMediaController(mMediaController);
526 }
527 getSherlockActivity().unbindService(mMediaServiceConnection);
528 mMediaServiceConnection = null;
529 mMediaServiceBinder = null;
530 }
531 }
532
533 @Override
534 public boolean onTouch(View v, MotionEvent event) {
535 if (event.getAction() == MotionEvent.ACTION_DOWN && v == mVideoPreview) {
536 startFullScreenVideo();
537 return true;
538 }
539 return false;
540 }
541
542
543 private void startFullScreenVideo() {
544 Intent i = new Intent(getSherlockActivity(), PreviewVideoActivity.class);
545 i.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
546 i.putExtra(FileActivity.EXTRA_FILE, getFile());
547 i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
548 mVideoPreview.pause();
549 i.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPreview.getCurrentPosition());
550 startActivityForResult(i, 0);
551 }
552
553 @Override
554 public void onConfigurationChanged (Configuration newConfig) {
555 Log_OC.e(TAG, "onConfigurationChanged " + this);
556 }
557
558 @Override
559 public void onActivityResult (int requestCode, int resultCode, Intent data) {
560 Log_OC.e(TAG, "onActivityResult " + this);
561 super.onActivityResult(requestCode, resultCode, data);
562 if (resultCode == Activity.RESULT_OK) {
563 mSavedPlaybackPosition = data.getExtras().getInt(PreviewVideoActivity.EXTRA_START_POSITION);
564 mAutoplay = data.getExtras().getBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY);
565 }
566 }
567
568
569 private void playAudio() {
570 OCFile file = getFile();
571 if (!mMediaServiceBinder.isPlaying(file)) {
572 Log_OC.d(TAG, "starting playback of " + file.getStoragePath());
573 mMediaServiceBinder.start(mAccount, file, mAutoplay, mSavedPlaybackPosition);
574
575 } else {
576 if (!mMediaServiceBinder.isPlaying() && mAutoplay) {
577 mMediaServiceBinder.start();
578 mMediaController.updatePausePlay();
579 }
580 }
581 }
582
583
584 private void bindMediaService() {
585 Log_OC.d(TAG, "Binding to MediaService...");
586 if (mMediaServiceConnection == null) {
587 mMediaServiceConnection = new MediaServiceConnection();
588 }
589 getSherlockActivity().bindService( new Intent(getSherlockActivity(),
590 MediaService.class),
591 mMediaServiceConnection,
592 Context.BIND_AUTO_CREATE);
593 // follow the flow in MediaServiceConnection#onServiceConnected(...)
594 }
595
596 /** Defines callbacks for service binding, passed to bindService() */
597 private class MediaServiceConnection implements ServiceConnection {
598
599 @Override
600 public void onServiceConnected(ComponentName component, IBinder service) {
601 if (getSherlockActivity() != null) {
602 if (component.equals(new ComponentName(getSherlockActivity(), MediaService.class))) {
603 Log_OC.d(TAG, "Media service connected");
604 mMediaServiceBinder = (MediaServiceBinder) service;
605 if (mMediaServiceBinder != null) {
606 prepareMediaController();
607 playAudio(); // do not wait for the touch of nobody to play audio
608
609 Log_OC.d(TAG, "Successfully bound to MediaService, MediaController ready");
610
611 } else {
612 Log_OC.e(TAG, "Unexpected response from MediaService while binding");
613 }
614 }
615 }
616 }
617
618 private void prepareMediaController() {
619 mMediaServiceBinder.registerMediaController(mMediaController);
620 if (mMediaController != null) {
621 mMediaController.setMediaPlayer(mMediaServiceBinder);
622 mMediaController.setEnabled(true);
623 mMediaController.updatePausePlay();
624 }
625 }
626
627 @Override
628 public void onServiceDisconnected(ComponentName component) {
629 if (component.equals(new ComponentName(getSherlockActivity(), MediaService.class))) {
630 Log_OC.e(TAG, "Media service suddenly disconnected");
631 if (mMediaController != null) {
632 mMediaController.setMediaPlayer(null);
633 } else {
634 Toast.makeText(getSherlockActivity(), "No media controller to release when disconnected from media service", Toast.LENGTH_SHORT).show();
635 }
636 mMediaServiceBinder = null;
637 mMediaServiceConnection = null;
638 }
639 }
640 }
641
642
643
644 /**
645 * Opens the previewed file with an external application.
646 *
647 * TODO - improve this; instead of prioritize the actions available for the MIME type in the server,
648 * we should get a list of available apps for MIME tpye in the server and join it with the list of
649 * available apps for the MIME type known from the file extension, to let the user choose
650 */
651 private void openFile() {
652 OCFile file = getFile();
653 stopPreview(true);
654 String storagePath = file.getStoragePath();
655 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
656 try {
657 Intent i = new Intent(Intent.ACTION_VIEW);
658 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
659 i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
660 startActivity(i);
661
662 } catch (Throwable t) {
663 Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file.getMimetype());
664 boolean toastIt = true;
665 String mimeType = "";
666 try {
667 Intent i = new Intent(Intent.ACTION_VIEW);
668 mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
669 if (mimeType == null || !mimeType.equals(file.getMimetype())) {
670 if (mimeType != null) {
671 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
672 } else {
673 // desperate try
674 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
675 }
676 i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
677 startActivity(i);
678 toastIt = false;
679 }
680
681 } catch (IndexOutOfBoundsException e) {
682 Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
683
684 } catch (ActivityNotFoundException e) {
685 Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
686
687 } catch (Throwable th) {
688 Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
689
690 } finally {
691 if (toastIt) {
692 Toast.makeText(getSherlockActivity(), "There is no application to handle file " + file.getFileName(), Toast.LENGTH_SHORT).show();
693 }
694 }
695
696 }
697 finish();
698 }
699
700 /**
701 * Starts a the removal of the previewed file.
702 *
703 * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
704 * depending upon the user selection in the dialog.
705 */
706 private void removeFile() {
707 ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
708 R.string.confirmation_remove_alert,
709 new String[]{getFile().getFileName()},
710 R.string.confirmation_remove_remote_and_local,
711 R.string.confirmation_remove_local,
712 R.string.common_cancel);
713 confDialog.setOnConfirmationListener(this);
714 confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
715 }
716
717
718 /**
719 * Performs the removal of the previewed file, both locally and in the server.
720 */
721 @Override
722 public void onConfirmation(String callerTag) {
723 OCFile file = getFile();
724 FileDataStorageManager storageManager =
725 ((FileActivity)getSherlockActivity()).getStorageManager();
726 if (storageManager.getFileById(file.getFileId()) != null) { // check that the file is still there;
727 stopPreview(true);
728 mLastRemoteOperation = new RemoveFileOperation( file, // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
729 true,
730 storageManager);
731 mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
732
733 ((FileActivity) getSherlockActivity()).showLoadingDialog();
734 }
735 }
736
737
738 /**
739 * Removes the file from local storage
740 */
741 @Override
742 public void onNeutral(String callerTag) {
743 OCFile file = getFile();
744 stopPreview(true);
745 ((FileActivity)getSherlockActivity()).getStorageManager().removeFile(file, false, true); // TODO perform in background task / new thread
746 finish();
747 }
748
749 /**
750 * User cancelled the removal action.
751 */
752 @Override
753 public void onCancel(String callerTag) {
754 // nothing to do here
755 }
756
757
758 /**
759 * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment} to be previewed.
760 *
761 * @param file File to test if can be previewed.
762 * @return 'True' if the file can be handled by the fragment.
763 */
764 public static boolean canBePreviewed(OCFile file) {
765 return (file != null && (file.isAudio() || file.isVideo()));
766 }
767
768 /**
769 * {@inheritDoc}
770 */
771 @Override
772 public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
773 if (operation.equals(mLastRemoteOperation)) {
774 if (operation instanceof RemoveFileOperation) {
775 onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
776 }
777 }
778 }
779
780 private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
781 ((FileActivity) getSherlockActivity()).dismissLoadingDialog();
782 if (result.isSuccess()) {
783 Toast msg = Toast.makeText(getSherlockActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
784 msg.show();
785 finish();
786
787 } else {
788 Toast msg = Toast.makeText(getSherlockActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG);
789 msg.show();
790 if (result.isSslRecoverableException()) {
791 // TODO show the SSL warning dialog
792 }
793 }
794 }
795
796 private void stopPreview(boolean stopAudio) {
797 OCFile file = getFile();
798 if (file.isAudio() && stopAudio) {
799 mMediaServiceBinder.pause();
800
801 } else if (file.isVideo()) {
802 mVideoPreview.stopPlayback();
803 }
804 }
805
806
807
808 /**
809 * Finishes the preview
810 */
811 private void finish() {
812 getSherlockActivity().onBackPressed();
813 }
814
815
816 public int getPosition() {
817 if (mPrepared) {
818 mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
819 }
820 Log_OC.e(TAG, "getting position: " + mSavedPlaybackPosition);
821 return mSavedPlaybackPosition;
822 }
823
824 public boolean isPlaying() {
825 if (mPrepared) {
826 mAutoplay = mVideoPreview.isPlaying();
827 }
828 return mAutoplay;
829 }
830
831 }