/* * This file is part of Popcorn Time. * * Popcorn Time is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Popcorn Time is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Popcorn Time. If not, see <http://www.gnu.org/licenses/>. */ package pct.droid.activities; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.MediaStore; import android.provider.OpenableColumns; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; import org.videolan.libvlc.util.AndroidUtil; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import pct.droid.R; import pct.droid.activities.base.PopcornBaseActivity; import pct.droid.base.fragments.BaseVideoPlayerFragment; import pct.droid.base.torrent.StreamInfo; import pct.droid.base.torrent.TorrentService; import pct.droid.fragments.dialog.OptionDialogFragment; import pct.droid.fragments.VideoPlayerFragment; import timber.log.Timber; public class VideoPlayerActivity extends PopcornBaseActivity implements VideoPlayerFragment.Callback { private VideoPlayerFragment mFragment; private StreamInfo mStreamInfo; private String mTitle = ""; private Long mResumePosition; public static Intent startActivity(Context context, @NonNull StreamInfo info) { return startActivity(context, info, 0); } public static Intent startActivity(Context context, @NonNull StreamInfo info, long resumePosition) { Intent i = new Intent(context, VideoPlayerActivity.class); if (info == null){ throw new IllegalArgumentException("StreamInfo must not be null"); } i.putExtra(INFO, info); i.putExtra(BaseVideoPlayerFragment.RESUME_POSITION, resumePosition); context.startActivity(i); return i; } public final static String INFO = "stream_info"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.activity_videoplayer); mFragment = (VideoPlayerFragment) getSupportFragmentManager().findFragmentById(R.id.video_fragment); setShowCasting(true); mResumePosition = getIntent().getLongExtra(BaseVideoPlayerFragment.RESUME_POSITION, 0); mStreamInfo = getIntent().getParcelableExtra(INFO); if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) { Bundle extras = getIntent().getExtras(); mStreamInfo = new StreamInfo(""); /* Started from external application 'content' */ Uri data = getIntent().getData(); if (data != null && TextUtils.equals(data.getScheme(), "content")) { // Mail-based apps - download the stream to a temporary file and play it if(data.getHost().equals("com.fsck.k9.attachmentprovider") || data.getHost().equals("gmail-ls")) { InputStream is = null; OutputStream os = null; try { Cursor cursor = getContentResolver().query(data, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null); if (cursor != null) { cursor.moveToFirst(); String filename = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)); cursor.close(); Timber.i("Getting file " + filename + " from content:// URI"); is = getContentResolver().openInputStream(data); os = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/Download/" + filename); byte[] buffer = new byte[1024]; int bytesRead = 0; while((bytesRead = is.read(buffer)) >= 0) { os.write(buffer, 0, bytesRead); } mStreamInfo.setVideoLocation(AndroidUtil.PathToUri(Environment.getExternalStorageDirectory().getPath() + "/Download/" + filename).toString()); } } catch (Exception e) { Timber.e("Couldn't download file from mail URI"); return; } finally { try { is.close(); os.close(); } catch (IOException e) { e.printStackTrace(); } } } // Media or MMS URI else if (TextUtils.equals(data.getAuthority(), "media")){ try { Cursor cursor = getContentResolver().query(data, new String[]{ MediaStore.Video.Media.DATA }, null, null, null); if (cursor != null) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA); if (cursor.moveToFirst()) mStreamInfo.setVideoLocation(AndroidUtil.PathToUri(cursor.getString(column_index)).toString()); cursor.close(); } // other content-based URI (probably file pickers) else { mStreamInfo.setVideoLocation(data.toString()); } } catch (Exception e) { mStreamInfo.setVideoLocation(data.toString()); if (data.getScheme() == null) mStreamInfo.setVideoLocation(AndroidUtil.PathToUri(data.getPath()).toString()); Timber.e("Couldn't read the file from media or MMS"); } } else { ParcelFileDescriptor inputPFD = null; try { inputPFD = getContentResolver().openFileDescriptor(data, "r"); if (AndroidUtil.isHoneycombMr1OrLater()) mStreamInfo.setVideoLocation(AndroidUtil.LocationToUri("fd://" + inputPFD.getFd()).toString()); else { String fdString = inputPFD.getFileDescriptor().toString(); mStreamInfo.setVideoLocation(AndroidUtil.LocationToUri("fd://" + fdString.substring(15, fdString.length() - 1)).toString()); } } catch (FileNotFoundException e) { Timber.e("Couldn't understand the intent"); return; } } } /* External application */ else if (getIntent().getDataString() != null) { // Plain URI final String location = getIntent().getDataString(); // Remove VLC prefix if needed if (location.startsWith("vlc://")) { mStreamInfo.setVideoLocation(AndroidUtil.LocationToUri(location.substring(6)).toString()); } else { data = getIntent().getData(); if (data.getScheme() == null) mStreamInfo.setVideoLocation(AndroidUtil.PathToUri(data.getPath()).toString()); else mStreamInfo.setVideoLocation(data.toString()); } } else { Timber.e("Couldn't understand the intent"); return; } // Try to get the position if(extras != null) mResumePosition = extras.getLong("position", -1); } if(mStreamInfo == null) { finish(); return; } mTitle = mStreamInfo.getTitle() == null ? getString(R.string.the_video) : mStreamInfo.getTitle(); } @Override protected void onResume() { super.onResume(); if(null != mService && mService.checkStopped()) finish(); } @Override protected void onPause() { if(mService != null) mService.removeListener(mFragment); super.onPause(); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: showExitDialog(); return true; } return super.onOptionsItemSelected(item); } @Override public void onBackPressed() { showExitDialog(); } private void showExitDialog() { OptionDialogFragment.show(getSupportFragmentManager(), getString(R.string.leave_videoplayer_title), String.format(getString(R.string.leave_videoplayer_message), mTitle), getString(android.R.string.yes), getString(android.R.string.no), new OptionDialogFragment.Listener() { @Override public void onSelectionPositive() { if (mService != null) mService.stopStreaming(); finish(); } @Override public void onSelectionNegative() { } }); } @Override public Long getResumePosition() { return mResumePosition; } @Override public StreamInfo getInfo() { return mStreamInfo; } @Override public TorrentService getService() { return mService; } @Override public void onTorrentServiceDisconnected() { if (null!=mFragment){ mService.removeListener(mFragment); } super.onTorrentServiceDisconnected(); } @Override public void onTorrentServiceConnected() { super.onTorrentServiceConnected(); if(mService.checkStopped()) { finish(); return; } mService.addListener(mFragment); } }