PreviewMediaFragment.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * ownCloud Android client application
  3. *
  4. * @author David A. Velasco
  5. * @author Chris Narkiewicz
  6. * @author Andy Scherzinger
  7. * Copyright (C) 2016 ownCloud Inc.
  8. * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
  9. * Copyright (C) 2020 Andy Scherzinger
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2,
  13. * as published by the Free Software Foundation.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. package com.owncloud.android.ui.preview;
  24. import android.app.Activity;
  25. import android.content.Context;
  26. import android.content.Intent;
  27. import android.content.res.Configuration;
  28. import android.content.res.Resources;
  29. import android.graphics.Bitmap;
  30. import android.graphics.BitmapFactory;
  31. import android.media.MediaMetadataRetriever;
  32. import android.net.Uri;
  33. import android.os.AsyncTask;
  34. import android.os.Bundle;
  35. import android.view.LayoutInflater;
  36. import android.view.Menu;
  37. import android.view.MenuInflater;
  38. import android.view.MenuItem;
  39. import android.view.MotionEvent;
  40. import android.view.View;
  41. import android.view.View.OnTouchListener;
  42. import android.view.ViewGroup;
  43. import android.widget.LinearLayout;
  44. import com.google.android.exoplayer2.MediaItem;
  45. import com.google.android.exoplayer2.SimpleExoPlayer;
  46. import com.google.android.exoplayer2.ui.StyledPlayerControlView;
  47. import com.nextcloud.client.account.User;
  48. import com.nextcloud.client.account.UserAccountManager;
  49. import com.nextcloud.client.di.Injectable;
  50. import com.nextcloud.client.media.PlayerServiceConnection;
  51. import com.nextcloud.client.network.ClientFactory;
  52. import com.owncloud.android.R;
  53. import com.owncloud.android.databinding.FragmentPreviewMediaBinding;
  54. import com.owncloud.android.datamodel.OCFile;
  55. import com.owncloud.android.datamodel.ThumbnailsCacheManager;
  56. import com.owncloud.android.files.FileMenuFilter;
  57. import com.owncloud.android.files.StreamMediaFileOperation;
  58. import com.owncloud.android.lib.common.OwnCloudClient;
  59. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  60. import com.owncloud.android.lib.common.utils.Log_OC;
  61. import com.owncloud.android.ui.activity.DrawerActivity;
  62. import com.owncloud.android.ui.activity.FileActivity;
  63. import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
  64. import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
  65. import com.owncloud.android.ui.fragment.FileFragment;
  66. import com.owncloud.android.utils.MimeTypeUtil;
  67. import java.lang.ref.WeakReference;
  68. import javax.inject.Inject;
  69. import androidx.annotation.NonNull;
  70. import androidx.annotation.StringRes;
  71. import androidx.drawerlayout.widget.DrawerLayout;
  72. /**
  73. * This fragment shows a preview of a downloaded media file (audio or video).
  74. * <p>
  75. * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link User} values will produce an {@link
  76. * IllegalStateException}.
  77. * <p>
  78. * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on
  79. * instantiation too.
  80. */
  81. public class PreviewMediaFragment extends FileFragment implements OnTouchListener,
  82. Injectable, StyledPlayerControlView.OnFullScreenModeChangedListener {
  83. private static final String TAG = PreviewMediaFragment.class.getSimpleName();
  84. public static final String EXTRA_FILE = "FILE";
  85. public static final String EXTRA_USER = "USER";
  86. private static final String EXTRA_PLAY_POSITION = "PLAY_POSITION";
  87. private static final String EXTRA_PLAYING = "PLAYING";
  88. private static final double MIN_DENSITY_RATIO = 24.0;
  89. private static final int MENU_FULLSCREEN_ID = 3344;
  90. private static final String FILE = "FILE";
  91. private static final String USER = "USER";
  92. private static final String PLAYBACK_POSITION = "PLAYBACK_POSITION";
  93. private static final String AUTOPLAY = "AUTOPLAY";
  94. private User user;
  95. private long savedPlaybackPosition;
  96. private boolean autoplay;
  97. private boolean prepared;
  98. private PlayerServiceConnection mediaPlayerServiceConnection;
  99. private Uri videoUri;
  100. @Inject ClientFactory clientFactory;
  101. @Inject UserAccountManager accountManager;
  102. FragmentPreviewMediaBinding binding;
  103. LinearLayout emptyListView;
  104. private SimpleExoPlayer exoPlayer;
  105. /**
  106. * Creates a fragment to preview a file.
  107. * <p>
  108. * When 'fileToDetail' or 'user' are null
  109. *
  110. * @param fileToDetail An {@link OCFile} to preview in the fragment
  111. * @param user Currently active user
  112. */
  113. public static PreviewMediaFragment newInstance(OCFile fileToDetail,
  114. User user,
  115. long startPlaybackPosition,
  116. boolean autoplay) {
  117. PreviewMediaFragment previewMediaFragment = new PreviewMediaFragment();
  118. Bundle bundle = new Bundle();
  119. bundle.putParcelable(FILE, fileToDetail);
  120. bundle.putParcelable(USER, user);
  121. bundle.putLong(PLAYBACK_POSITION, startPlaybackPosition);
  122. bundle.putBoolean(AUTOPLAY, autoplay);
  123. previewMediaFragment.setArguments(bundle);
  124. return previewMediaFragment;
  125. }
  126. /**
  127. * Creates an empty fragment for previews.
  128. * <p/>
  129. * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the
  130. * device is turned a aside).
  131. * <p/>
  132. * DO NOT CALL IT: an {@link OCFile} and {@link User} must be provided for a successful construction
  133. */
  134. public PreviewMediaFragment() {
  135. super();
  136. savedPlaybackPosition = 0;
  137. autoplay = true;
  138. }
  139. @Override
  140. public void onCreate(Bundle savedInstanceState) {
  141. super.onCreate(savedInstanceState);
  142. setHasOptionsMenu(true);
  143. Bundle bundle = getArguments();
  144. setFile(bundle.getParcelable(FILE));
  145. user = bundle.getParcelable(USER);
  146. savedPlaybackPosition = bundle.getLong(PLAYBACK_POSITION);
  147. autoplay = bundle.getBoolean(AUTOPLAY);
  148. mediaPlayerServiceConnection = new PlayerServiceConnection(getContext());
  149. }
  150. @Override
  151. public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  152. super.onCreateView(inflater, container, savedInstanceState);
  153. Log_OC.v(TAG, "onCreateView");
  154. binding = FragmentPreviewMediaBinding.inflate(inflater, container, false);
  155. View view = binding.getRoot();
  156. emptyListView = binding.emptyView.emptyListView;
  157. setLoadingView();
  158. return view;
  159. }
  160. private void setLoadingView() {
  161. binding.progress.setVisibility(View.VISIBLE);
  162. binding.emptyView.emptyListView.setVisibility(View.GONE);
  163. }
  164. private void setVideoErrorMessage(String headline, @StringRes int message) {
  165. binding.emptyView.emptyListViewHeadline.setText(headline);
  166. binding.emptyView.emptyListViewText.setText(message);
  167. binding.emptyView.emptyListIcon.setImageResource(R.drawable.file_movie);
  168. binding.emptyView.emptyListViewText.setVisibility(View.VISIBLE);
  169. binding.emptyView.emptyListIcon.setVisibility(View.VISIBLE);
  170. binding.progress.setVisibility(View.GONE);
  171. binding.emptyView.emptyListView.setVisibility(View.VISIBLE);
  172. }
  173. @Override
  174. public void onActivityCreated(Bundle savedInstanceState) {
  175. super.onActivityCreated(savedInstanceState);
  176. Log_OC.v(TAG, "onActivityCreated");
  177. OCFile file = getFile();
  178. if (savedInstanceState == null) {
  179. if (file == null) {
  180. throw new IllegalStateException("Instanced with a NULL OCFile");
  181. }
  182. if (user == null) {
  183. throw new IllegalStateException("Instanced with a NULL ownCloud Account");
  184. }
  185. } else {
  186. file = savedInstanceState.getParcelable(EXTRA_FILE);
  187. setFile(file);
  188. user = savedInstanceState.getParcelable(EXTRA_USER);
  189. savedPlaybackPosition = savedInstanceState.getInt(EXTRA_PLAY_POSITION);
  190. autoplay = savedInstanceState.getBoolean(EXTRA_PLAYING);
  191. }
  192. if (file != null) {
  193. if (MimeTypeUtil.isVideo(file)) {
  194. binding.exoplayerView.setVisibility(View.VISIBLE);
  195. binding.imagePreview.setVisibility(View.GONE);
  196. } else {
  197. binding.exoplayerView.setVisibility(View.GONE);
  198. binding.imagePreview.setVisibility(View.VISIBLE);
  199. extractAndSetCoverArt(file);
  200. }
  201. }
  202. toggleDrawerLockMode(containerActivity, DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
  203. }
  204. /**
  205. * tries to read the cover art from the audio file and sets it as cover art.
  206. *
  207. * @param file audio file with potential cover art
  208. */
  209. private void extractAndSetCoverArt(OCFile file) {
  210. if (MimeTypeUtil.isAudio(file)) {
  211. if (file.getStoragePath() == null) {
  212. setThumbnailForAudio(file);
  213. } else {
  214. try {
  215. MediaMetadataRetriever mmr = new MediaMetadataRetriever();
  216. mmr.setDataSource(file.getStoragePath());
  217. byte[] data = mmr.getEmbeddedPicture();
  218. if (data != null) {
  219. Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
  220. binding.imagePreview.setImageBitmap(bitmap); //associated cover art in bitmap
  221. } else {
  222. setThumbnailForAudio(file);
  223. }
  224. } catch (Throwable t) {
  225. binding.imagePreview.setImageResource(R.drawable.logo);
  226. }
  227. }
  228. }
  229. }
  230. private void setThumbnailForAudio(OCFile file) {
  231. Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
  232. ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.getRemoteId());
  233. if (thumbnail != null) {
  234. binding.imagePreview.setImageBitmap(thumbnail);
  235. } else {
  236. binding.imagePreview.setImageResource(R.drawable.logo);
  237. }
  238. }
  239. @Override
  240. public void onSaveInstanceState(@NonNull Bundle outState) {
  241. super.onSaveInstanceState(outState);
  242. Log_OC.v(TAG, "onSaveInstanceState");
  243. toggleDrawerLockMode(containerActivity, DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
  244. outState.putParcelable(EXTRA_FILE, getFile());
  245. outState.putParcelable(EXTRA_USER, user);
  246. if (MimeTypeUtil.isVideo(getFile())) {
  247. savedPlaybackPosition = exoPlayer.getCurrentPosition();
  248. autoplay = exoPlayer.isPlaying();
  249. outState.putLong(EXTRA_PLAY_POSITION, savedPlaybackPosition);
  250. outState.putBoolean(EXTRA_PLAYING, autoplay);
  251. } else if (mediaPlayerServiceConnection.isConnected()) {
  252. outState.putInt(EXTRA_PLAY_POSITION, mediaPlayerServiceConnection.getCurrentPosition());
  253. outState.putBoolean(EXTRA_PLAYING, mediaPlayerServiceConnection.isPlaying());
  254. }
  255. }
  256. @Override
  257. public void onStart() {
  258. super.onStart();
  259. Log_OC.v(TAG, "onStart");
  260. OCFile file = getFile();
  261. if (file != null) {
  262. // bind to any existing player
  263. mediaPlayerServiceConnection.bind();
  264. exoPlayer = new SimpleExoPlayer.Builder(getContext()).build();
  265. binding.exoplayerView.setPlayer(exoPlayer);
  266. if (MimeTypeUtil.isAudio(file)) {
  267. binding.mediaController.setMediaPlayer(mediaPlayerServiceConnection);
  268. binding.mediaController.setVisibility(View.VISIBLE);
  269. mediaPlayerServiceConnection.start(user, file, autoplay, savedPlaybackPosition);
  270. binding.emptyView.emptyListView.setVisibility(View.GONE);
  271. binding.progress.setVisibility(View.GONE);
  272. } else if (MimeTypeUtil.isVideo(file)) {
  273. if (mediaPlayerServiceConnection.isConnected()) {
  274. // always stop player
  275. stopAudio();
  276. }
  277. playVideo();
  278. }
  279. }
  280. }
  281. private void stopAudio() {
  282. mediaPlayerServiceConnection.stop();
  283. }
  284. @Override
  285. public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
  286. super.onCreateOptionsMenu(menu, inflater);
  287. menu.removeItem(R.id.action_search);
  288. menu.add(Menu.NONE, MENU_FULLSCREEN_ID, 99, R.string.fullscreen);
  289. inflater.inflate(R.menu.item_file, menu);
  290. }
  291. @Override
  292. public void onPrepareOptionsMenu(@NonNull Menu menu) {
  293. super.onPrepareOptionsMenu(menu);
  294. if (containerActivity.getStorageManager() != null) {
  295. User currentUser = accountManager.getUser();
  296. FileMenuFilter mf = new FileMenuFilter(
  297. getFile(),
  298. containerActivity,
  299. getActivity(),
  300. false,
  301. currentUser
  302. );
  303. mf.filter(menu, true);
  304. }
  305. // additional restriction for this fragment
  306. // TODO allow renaming in PreviewImageFragment
  307. MenuItem item = menu.findItem(R.id.action_rename_file);
  308. if (item != null) {
  309. item.setVisible(false);
  310. item.setEnabled(false);
  311. }
  312. // additional restriction for this fragment
  313. item = menu.findItem(R.id.action_select_all);
  314. if (item != null) {
  315. item.setVisible(false);
  316. item.setEnabled(false);
  317. }
  318. // additional restriction for this fragment
  319. item = menu.findItem(R.id.action_move);
  320. if (item != null) {
  321. item.setVisible(false);
  322. item.setEnabled(false);
  323. }
  324. // additional restriction for this fragment
  325. item = menu.findItem(R.id.action_copy);
  326. if (item != null) {
  327. item.setVisible(false);
  328. item.setEnabled(false);
  329. }
  330. // additional restriction for this fragment
  331. item = menu.findItem(R.id.action_favorite);
  332. if (item != null) {
  333. item.setVisible(false);
  334. item.setEnabled(false);
  335. }
  336. // additional restriction for this fragment
  337. item = menu.findItem(R.id.action_unset_favorite);
  338. if (item != null) {
  339. item.setVisible(false);
  340. item.setEnabled(false);
  341. }
  342. if (getFile().isSharedWithMe() && !getFile().canReshare()) {
  343. // additional restriction for this fragment
  344. item = menu.findItem(R.id.action_send_share_file);
  345. if (item != null) {
  346. item.setVisible(false);
  347. item.setEnabled(false);
  348. }
  349. }
  350. }
  351. @Override
  352. public boolean onOptionsItemSelected(MenuItem item) {
  353. int itemId = item.getItemId();
  354. if (itemId == R.id.action_send_share_file) {
  355. sendShareFile();
  356. return true;
  357. } else if (itemId == R.id.action_open_file_with) {
  358. openFile();
  359. return true;
  360. } else if (itemId == R.id.action_remove_file) {
  361. RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(getFile());
  362. dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
  363. return true;
  364. } else if (itemId == R.id.action_see_details) {
  365. seeDetails();
  366. return true;
  367. } else if (itemId == R.id.action_sync_file) {
  368. containerActivity.getFileOperationsHelper().syncFile(getFile());
  369. return true;
  370. } else if (itemId == MENU_FULLSCREEN_ID) {
  371. startFullScreenVideo();
  372. return true;
  373. }
  374. return super.onOptionsItemSelected(item);
  375. }
  376. /**
  377. * Update the file of the fragment with file value
  378. *
  379. * @param file Replaces the held file with a new one
  380. */
  381. public void updateFile(OCFile file) {
  382. setFile(file);
  383. }
  384. private void seeDetails() {
  385. stopPreview(false);
  386. containerActivity.showDetails(getFile());
  387. }
  388. private void sendShareFile() {
  389. stopPreview(false);
  390. containerActivity.getFileOperationsHelper().sendShareFile(getFile());
  391. }
  392. private void playVideo() {
  393. // load the video file in the video player
  394. // when done, VideoHelper#onPrepared() will be called
  395. if (getFile().isDown()) {
  396. binding.progress.setVisibility(View.GONE);
  397. exoPlayer.addMediaItem(MediaItem.fromUri(getFile().getStorageUri()));
  398. exoPlayer.prepare();
  399. if (savedPlaybackPosition >= 0) {
  400. exoPlayer.seekTo(savedPlaybackPosition);
  401. }
  402. exoPlayer.play();
  403. } else {
  404. try {
  405. new LoadStreamUrl(this, user, clientFactory).execute(getFile().getLocalId());
  406. } catch (Exception e) {
  407. Log_OC.e(TAG, "Loading stream url not possible: " + e);
  408. }
  409. }
  410. }
  411. @Override
  412. public void onFullScreenModeChanged(boolean isFullScreen) {
  413. Log_OC.e(TAG, "Fullscreen: " + isFullScreen);
  414. }
  415. private static class LoadStreamUrl extends AsyncTask<String, Void, Uri> {
  416. private final ClientFactory clientFactory;
  417. private final User user;
  418. private final WeakReference<PreviewMediaFragment> previewMediaFragmentWeakReference;
  419. public LoadStreamUrl(PreviewMediaFragment previewMediaFragment, User user, ClientFactory clientFactory) {
  420. this.previewMediaFragmentWeakReference = new WeakReference<>(previewMediaFragment);
  421. this.user = user;
  422. this.clientFactory = clientFactory;
  423. }
  424. @Override
  425. protected Uri doInBackground(String... fileId) {
  426. OwnCloudClient client;
  427. try {
  428. client = clientFactory.create(user);
  429. } catch (ClientFactory.CreationException e) {
  430. Log_OC.e(TAG, "Loading stream url not possible: " + e);
  431. return null;
  432. }
  433. StreamMediaFileOperation sfo = new StreamMediaFileOperation(fileId[0]);
  434. RemoteOperationResult result = sfo.execute(client);
  435. if (!result.isSuccess()) {
  436. return null;
  437. }
  438. return Uri.parse((String) result.getData().get(0));
  439. }
  440. @Override
  441. protected void onPostExecute(Uri uri) {
  442. final PreviewMediaFragment previewMediaFragment = previewMediaFragmentWeakReference.get();
  443. final Context context = previewMediaFragment != null ? previewMediaFragment.getContext() : null;
  444. if (previewMediaFragment != null && previewMediaFragment.binding != null && context != null) {
  445. if (uri != null) {
  446. previewMediaFragment.videoUri = uri;
  447. previewMediaFragment.binding.progress.setVisibility(View.GONE);
  448. previewMediaFragment.exoPlayer.addMediaItem(MediaItem.fromUri(uri));
  449. previewMediaFragment.exoPlayer.prepare();
  450. previewMediaFragment.exoPlayer.play();
  451. } else {
  452. previewMediaFragment.emptyListView.setVisibility(View.VISIBLE);
  453. previewMediaFragment.setVideoErrorMessage(
  454. previewMediaFragment.getString(R.string.stream_not_possible_headline),
  455. R.string.stream_not_possible_message);
  456. }
  457. } else {
  458. Log_OC.e(TAG, "Error streaming file: no previewMediaFragment!");
  459. }
  460. }
  461. }
  462. @Override
  463. public void onPause() {
  464. Log_OC.v(TAG, "onPause");
  465. super.onPause();
  466. }
  467. @Override
  468. public void onResume() {
  469. super.onResume();
  470. autoplay = false;
  471. Log_OC.v(TAG, "onResume");
  472. }
  473. @Override
  474. public void onDestroy() {
  475. Log_OC.v(TAG, "onDestroy");
  476. super.onDestroy();
  477. }
  478. @Override
  479. public void onDestroyView() {
  480. Log_OC.v(TAG, "onDestroyView");
  481. super.onDestroyView();
  482. binding = null;
  483. }
  484. @Override
  485. public void onStop() {
  486. Log_OC.v(TAG, "onStop");
  487. if (MimeTypeUtil.isAudio(getFile()) && !mediaPlayerServiceConnection.isPlaying()) {
  488. stopAudio();
  489. }
  490. mediaPlayerServiceConnection.unbind();
  491. toggleDrawerLockMode(containerActivity, DrawerLayout.LOCK_MODE_UNLOCKED);
  492. super.onStop();
  493. }
  494. @Override
  495. public boolean onTouch(View v, MotionEvent event) {
  496. if (event.getAction() == MotionEvent.ACTION_DOWN && v.equals(binding.exoplayerView)) {
  497. // added a margin on the left to avoid interfering with gesture to open navigation drawer
  498. if (event.getX() / Resources.getSystem().getDisplayMetrics().density > MIN_DENSITY_RATIO) {
  499. startFullScreenVideo();
  500. }
  501. return true;
  502. }
  503. return false;
  504. }
  505. private void startFullScreenVideo() {
  506. Intent intent = new Intent(getActivity(), PreviewVideoActivity.class);
  507. intent.putExtra(FileActivity.EXTRA_ACCOUNT, user.toPlatformAccount());
  508. intent.putExtra(FileActivity.EXTRA_FILE, getFile());
  509. intent.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, exoPlayer.isPlaying());
  510. intent.putExtra(PreviewVideoActivity.EXTRA_STREAM_URL, videoUri);
  511. exoPlayer.pause();
  512. intent.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, exoPlayer.getCurrentPosition());
  513. startActivityForResult(intent, FileActivity.REQUEST_CODE__LAST_SHARED + 1);
  514. }
  515. @Override
  516. public void onConfigurationChanged(@NonNull Configuration newConfig) {
  517. super.onConfigurationChanged(newConfig);
  518. Log_OC.v(TAG, "onConfigurationChanged " + this);
  519. }
  520. @Override
  521. public void onActivityResult(int requestCode, int resultCode, Intent data) {
  522. Log_OC.v(TAG, "onActivityResult " + this);
  523. super.onActivityResult(requestCode, resultCode, data);
  524. if (resultCode == Activity.RESULT_OK) {
  525. savedPlaybackPosition = data.getLongExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
  526. autoplay = data.getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, false);
  527. }
  528. }
  529. /**
  530. * Opens the previewed file with an external application.
  531. */
  532. private void openFile() {
  533. stopPreview(true);
  534. containerActivity.getFileOperationsHelper().openFile(getFile());
  535. finishPreview();
  536. }
  537. /**
  538. * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment} to be previewed.
  539. *
  540. * @param file File to test if can be previewed.
  541. * @return 'True' if the file can be handled by the fragment.
  542. */
  543. public static boolean canBePreviewed(OCFile file) {
  544. return file != null && (MimeTypeUtil.isAudio(file) || MimeTypeUtil.isVideo(file));
  545. }
  546. public void stopPreview(boolean stopAudio) {
  547. OCFile file = getFile();
  548. if (MimeTypeUtil.isAudio(file) && stopAudio) {
  549. mediaPlayerServiceConnection.pause();
  550. } else if (MimeTypeUtil.isVideo(file)) {
  551. exoPlayer.stop(true);
  552. }
  553. }
  554. /**
  555. * Finishes the preview
  556. */
  557. private void finishPreview() {
  558. final Activity activity = getActivity();
  559. if (activity != null) {
  560. activity.onBackPressed();
  561. }
  562. }
  563. public long getPosition() {
  564. if (prepared) {
  565. savedPlaybackPosition = exoPlayer.getCurrentPosition();
  566. }
  567. Log_OC.v(TAG, "getting position: " + savedPlaybackPosition);
  568. return savedPlaybackPosition;
  569. }
  570. private void toggleDrawerLockMode(ContainerActivity containerActivity, int lockMode) {
  571. ((DrawerActivity) containerActivity).setDrawerLockMode(lockMode);
  572. }
  573. @Override
  574. public void onDetach() {
  575. exoPlayer.stop();
  576. exoPlayer.release();
  577. super.onDetach();
  578. }
  579. }