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