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