/*****************************************************************************
* MediaInfoActivity.java
*****************************************************************************
* Copyright © 2011-2015 VLC authors and VideoLAN
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.gui.video;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ListFragment;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.util.Extensions;
import org.videolan.libvlc.util.VLCUtil;
import org.videolan.vlc.MediaLibrary;
import org.videolan.vlc.MediaWrapper;
import org.videolan.vlc.R;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.util.BitmapUtil;
import org.videolan.vlc.util.Strings;
import org.videolan.vlc.util.Util;
import org.videolan.vlc.util.VLCInstance;
import org.videolan.vlc.util.WeakHandler;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MediaInfoFragment extends ListFragment {
public final static String TAG = "VLC/MediaInfoFragment";
public final static String ITEM_KEY = "key_item";
private MediaWrapper mItem;
private Bitmap mImage;
private TextView mLengthView;
private TextView mSizeView;
private TextView mPathView;
private FloatingActionButton mPlayButton;
private ImageButton mDelete;
private ImageView mSubtitles;
private Media mMedia;
private MediaInfoAdapter mAdapter;
private final static int NEW_IMAGE = 0;
private final static int NEW_TEXT = 1;
private final static int NEW_SIZE = 2;
private final static int HIDE_DELETE = 3;
private final static int EXIT = 4;
private final static int SHOW_SUBTITLES = 5;
ExecutorService mThreadPoolExecutor;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
mItem = savedInstanceState.getParcelable(ITEM_KEY);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View v = inflater.inflate(R.layout.media_info, container, false);
mLengthView = (TextView) v.findViewById(R.id.length);
mSizeView = (TextView) v.findViewById(R.id.size_value);
mPathView = (TextView) v.findViewById(R.id.info_path);
mPlayButton = (FloatingActionButton) v.findViewById(R.id.play);
mDelete = (ImageButton) v.findViewById(R.id.info_delete);
mSubtitles = (ImageView) v.findViewById(R.id.info_subtitles);
mThreadPoolExecutor = Executors.newFixedThreadPool(2);
mThreadPoolExecutor.submit(mCheckFile);
mThreadPoolExecutor.submit(mLoadImage);
mPathView.setText(mItem == null ? "" : Uri.decode(mItem.getLocation().substring(7)));
mPlayButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
VideoPlayerActivity.start(getActivity(), mItem.getUri());
}
});
mDelete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mItem != null) {
VLCApplication.runBackground(new Runnable() {
@Override
public void run() {
boolean deleted = Util.deleteFile(mItem.getLocation());
if (deleted) {
mHandler.obtainMessage(EXIT).sendToTarget();
}
}
});
}
}
});
mAdapter = new MediaInfoAdapter(getActivity());
setListAdapter(mAdapter);
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mItem == null) {
// Shouldn't happen, maybe user opened it faster than Media Library could index it
return;
}
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(mItem.getTitle());
mLengthView.setText(Strings.millisToString(mItem.getLength()));
}
public void onStop(){
super.onStop();
if (mThreadPoolExecutor != null)
mThreadPoolExecutor.shutdownNow();
if (mMedia != null)
mMedia.release();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(ITEM_KEY, mItem);
}
public void setMediaLocation(String MRL) {
if (MRL == null)
return;
mItem = MediaLibrary.getInstance().getMediaItem(MRL);
}
Runnable mCheckFile = new Runnable() {
@Override
public void run() {
File itemFile = new File(Uri.decode(mItem.getLocation().substring(5)));
if (!itemFile.canWrite())
mHandler.obtainMessage(HIDE_DELETE).sendToTarget();
long length = itemFile.length();
mHandler.obtainMessage(NEW_SIZE, Long.valueOf(length)).sendToTarget();
checkSubtitles(itemFile);
}
};
private void checkSubtitles(File itemFile) {
String extension, filename, videoName = Uri.decode(itemFile.getName()), parentPath = Uri.decode(itemFile.getParent());
videoName = videoName.substring(0, videoName.lastIndexOf('.'));
String[] subFolders = {"/Subtitles", "/subtitles", "/Subs", "/subs"};
String[] files = itemFile.getParentFile().list();
int filesLength = files == null ? 0 : files.length;
for (int i = 0 ; i < subFolders.length ; ++i){
File subFolder = new File(parentPath+subFolders[i]);
if (!subFolder.exists())
continue;
String[] subFiles = subFolder.list();
int subFilesLength = 0;
String[] newFiles = new String[0];
if (subFiles != null) {
subFilesLength = subFiles.length;
newFiles = new String[filesLength+subFilesLength];
System.arraycopy(subFiles, 0, newFiles, 0, subFilesLength);
}
if (files != null)
System.arraycopy(files, 0, newFiles, subFilesLength, filesLength);
files = newFiles;
filesLength = files.length;
}
for (int i = 0; i<filesLength ; ++i){
filename = Uri.decode(files[i]);
int index = filename.lastIndexOf('.');
if (index <= 0)
continue;
extension = filename.substring(index);
if (!Extensions.SUBTITLES.contains(extension))
continue;
if (filename.startsWith(videoName)) {
mHandler.obtainMessage(SHOW_SUBTITLES).sendToTarget();
return;
}
}
}
Runnable mLoadImage = new Runnable() {
@Override
public void run() {
final LibVLC libVlc = VLCInstance.get();
if (libVlc == null)
return;
mMedia = new Media(libVlc, mItem.getUri());
mMedia.parse();
int videoHeight = mItem.getHeight();
int videoWidth = mItem.getWidth();
if (videoWidth == 0 || videoHeight == 0) {
//FIXME : find a better way to display media info without video size
videoWidth = 16;
videoHeight = 9;
}
mHandler.sendEmptyMessage(NEW_TEXT);
DisplayMetrics screen = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(screen);
int width, height;
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
width = Math.min(screen.widthPixels, screen.heightPixels);
} else {
width = screen.widthPixels /2 ;
}
height = width * videoHeight/videoWidth;
// Get the thumbnail.
mImage = Bitmap.createBitmap(width, height, Config.ARGB_8888);
byte[] b = VLCUtil.getThumbnail(mMedia, width, height);
if (b == null) // We were not able to create a thumbnail for this item.
return;
if (Thread.interrupted()) {
return;
}
mImage.copyPixelsFromBuffer(ByteBuffer.wrap(b));
mImage = BitmapUtil.cropBorders(mImage, width, height);
mHandler.sendEmptyMessage(NEW_IMAGE);
}
};
private void updateImage() {
if (getView() == null)
return;
ImageView imageView = (ImageView) getView().findViewById(R.id.image);
imageView.setImageBitmap(mImage);
ViewGroup.LayoutParams lp = imageView.getLayoutParams();
lp.height = mImage.getHeight();
lp.width = mImage.getWidth();
imageView.setLayoutParams(lp);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
mPlayButton.setVisibility(View.VISIBLE);
mLengthView.setVisibility(View.VISIBLE);
}
private void updateText() {
boolean hasSubs = false;
if (mMedia == null)
return;
final int trackCount = mMedia.getTrackCount();
for (int i = 0; i < trackCount; ++i) {
final Media.Track track = mMedia.getTrack(i);
if (track.type == Media.Track.Type.Text)
hasSubs = true;
mAdapter.add(track);
}
if (mAdapter.isEmpty()) {
getActivity().finish();
return;
}
if (hasSubs)
mHandler.obtainMessage(SHOW_SUBTITLES).sendToTarget();
}
private void updateSize(Long size){
mSizeView.setText(Strings.readableFileSize(size.longValue()));
}
private Handler mHandler = new MediaInfoHandler(this);
private static class MediaInfoHandler extends WeakHandler<MediaInfoFragment> {
public MediaInfoHandler(MediaInfoFragment owner) {
super(owner);
}
@Override
public void handleMessage(Message msg) {
MediaInfoFragment fragment = getOwner();
if(fragment == null) return;
switch (msg.what) {
case NEW_IMAGE:
fragment.updateImage();
break;
case NEW_TEXT:
fragment.updateText();
break;
case NEW_SIZE:
fragment.updateSize((Long) msg.obj);
break;
case HIDE_DELETE:
fragment.mDelete.setClickable(false);
fragment.mDelete.setVisibility(View.GONE);
break;
case EXIT:
fragment.getActivity().finish();
MediaLibrary.getInstance().scanMediaItems(true);
break;
case SHOW_SUBTITLES:
fragment.mSubtitles.setVisibility(View.VISIBLE);
break;
}
};
};
}