IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]第三篇、vlc-android之UDP组播使用

    cuiran发表于 2014-10-28 21:59:35
    love 0

    vlc-android 非常的强大,目前我们主要是使用vlc来播送组播UDP TS流。类似地址:udp://@239.1.1.0:2860这样的地址。在此之前发现声音会卡顿,效果不太好。今天发现是底层驱动的问题。

    但是在进行vlc stop时候不能进行资源释放,很是奇怪。明天解决这个问题。文章后续会继续整理!!!

    ---------------------------------------------------------------------------

    针对此前遇到vlc stop时候不能进行资源释放,后来是参考了VLC-android的源码,

    具体类文件目录是:


    类的代码:看一下VLC是如何释放的,这样处理逻辑比较好。

    /*****************************************************************************
     * VideoPlayerActivity.java
     *****************************************************************************
     * Copyright © 2011-2014 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 java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.OutputStream;
    import java.io.StreamCorruptedException;
    import java.io.UnsupportedEncodingException;
    import java.lang.reflect.Method;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.Locale;
    import java.util.Map;
    
    import org.videolan.libvlc.EventHandler;
    import org.videolan.libvlc.IVideoPlayer;
    import org.videolan.libvlc.LibVLC;
    import org.videolan.libvlc.LibVlcException;
    import org.videolan.libvlc.LibVlcUtil;
    import org.videolan.libvlc.Media;
    import org.videolan.vlc.MediaDatabase;
    import org.videolan.vlc.R;
    import org.videolan.vlc.VLCApplication;
    import org.videolan.vlc.audio.AudioServiceController;
    import org.videolan.vlc.gui.CommonDialogs;
    import org.videolan.vlc.gui.CommonDialogs.MenuType;
    import org.videolan.vlc.gui.MainActivity;
    import org.videolan.vlc.gui.PreferencesActivity;
    import org.videolan.vlc.util.AndroidDevices;
    import org.videolan.vlc.util.Strings;
    import org.videolan.vlc.util.VLCInstance;
    import org.videolan.vlc.util.WeakHandler;
    
    import android.annotation.TargetApi;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.app.KeyguardManager;
    import android.app.Presentation;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;
    import android.content.pm.ActivityInfo;
    import android.content.res.Configuration;
    import android.database.Cursor;
    import android.graphics.Color;
    import android.graphics.ImageFormat;
    import android.graphics.PixelFormat;
    import android.media.AudioManager;
    import android.media.AudioManager.OnAudioFocusChangeListener;
    import android.media.MediaRouter;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Message;
    import android.preference.PreferenceManager;
    import android.provider.MediaStore;
    import android.provider.Settings.SettingNotFoundException;
    import android.text.format.DateFormat;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.Display;
    import android.view.MotionEvent;
    import android.view.Surface;
    import android.view.SurfaceHolder;
    import android.view.SurfaceHolder.Callback;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnSystemUiVisibilityChangeListener;
    import android.view.ViewGroup.LayoutParams;
    import android.view.WindowManager;
    import android.view.animation.Animation;
    import android.view.animation.AnimationSet;
    import android.view.animation.AnimationUtils;
    import android.view.animation.DecelerateInterpolator;
    import android.view.animation.RotateAnimation;
    import android.widget.FrameLayout;
    import android.widget.ImageButton;
    import android.widget.ImageView;
    import android.widget.SeekBar;
    import android.widget.SeekBar.OnSeekBarChangeListener;
    import android.widget.TextView;
    
    public class VideoPlayerActivity extends Activity implements IVideoPlayer {
        public final static String TAG = "VLC/VideoPlayerActivity";
    
        // Internal intent identifier to distinguish between internal launch and
        // external intent.
        private final static String PLAY_FROM_VIDEOGRID = "org.videolan.vlc.gui.video.PLAY_FROM_VIDEOGRID";
    
        private SurfaceView mSurface;
        private SurfaceView mSubtitlesSurface;
        private SurfaceHolder mSurfaceHolder;
        private SurfaceHolder mSubtitlesSurfaceHolder;
        private FrameLayout mSurfaceFrame;
        private MediaRouter mMediaRouter;
        private MediaRouter.SimpleCallback mMediaRouterCallback;
        private SecondaryDisplay mPresentation;
        private LibVLC mLibVLC;
        private String mLocation;
    
        private static final int SURFACE_BEST_FIT = 0;
        private static final int SURFACE_FIT_HORIZONTAL = 1;
        private static final int SURFACE_FIT_VERTICAL = 2;
        private static final int SURFACE_FILL = 3;
        private static final int SURFACE_16_9 = 4;
        private static final int SURFACE_4_3 = 5;
        private static final int SURFACE_ORIGINAL = 6;
        private int mCurrentSize = SURFACE_BEST_FIT;
    
        private SharedPreferences mSettings;
    
        /** Overlay */
        private View mOverlayHeader;
        private View mOverlayOption;
        private View mOverlayProgress;
        private View mOverlayBackground;
        private static final int OVERLAY_TIMEOUT = 4000;
        private static final int OVERLAY_INFINITE = 3600000;
        private static final int FADE_OUT = 1;
        private static final int SHOW_PROGRESS = 2;
        private static final int SURFACE_SIZE = 3;
        private static final int AUDIO_SERVICE_CONNECTION_SUCCESS = 5;
        private static final int AUDIO_SERVICE_CONNECTION_FAILED = 6;
        private static final int FADE_OUT_INFO = 4;
        private boolean mDragging;
        private boolean mShowing;
        private int mUiVisibility = -1;
        private SeekBar mSeekbar;
        private TextView mTitle;
        private TextView mSysTime;
        private TextView mBattery;
        private TextView mTime;
        private TextView mLength;
        private TextView mInfo;
        private ImageView mLoading;
        private TextView mLoadingText;
        private ImageButton mPlayPause;
        private ImageButton mBackward;
        private ImageButton mForward;
        private boolean mEnableJumpButtons;
        private boolean mEnableBrightnessGesture;
        private boolean mEnableCloneMode;
        private boolean mDisplayRemainingTime = false;
        private int mScreenOrientation;
        private ImageButton mAudioTrack;
        private ImageButton mSubtitle;
        private ImageButton mLock;
        private ImageButton mSize;
        private ImageButton mMenu;
        private boolean mIsLocked = false;
        private int mLastAudioTrack = -1;
        private int mLastSpuTrack = -2;
    
        /**
         * For uninterrupted switching between audio and video mode
         */
        private boolean mSwitchingView;
        private boolean mEndReached;
        private boolean mCanSeek;
    
        // Playlist
        private int savedIndexPosition = -1;
    
        // size of the video
        private int mVideoHeight;
        private int mVideoWidth;
        private int mVideoVisibleHeight;
        private int mVideoVisibleWidth;
        private int mSarNum;
        private int mSarDen;
    
        //Volume
        private AudioManager mAudioManager;
        private int mAudioMax;
        private OnAudioFocusChangeListener mAudioFocusListener;
    
        //Touch Events
        private static final int TOUCH_NONE = 0;
        private static final int TOUCH_VOLUME = 1;
        private static final int TOUCH_BRIGHTNESS = 2;
        private static final int TOUCH_SEEK = 3;
        private int mTouchAction;
        private int mSurfaceYDisplayRange;
        private float mTouchY, mTouchX, mVol;
    
        // Brightness
        private boolean mIsFirstBrightnessGesture = true;
    
        // Tracks & Subtitles
        private Map mAudioTracksList;
        private Map mSubtitleTracksList;
        /**
         * Used to store a selected subtitle; see onActivityResult.
         * It is possible to have multiple custom subs in one session
         * (just like desktop VLC allows you as well.)
         */
        private final ArrayList mSubtitleSelectedFiles = new ArrayList();
    
        // Whether fallback from HW acceleration to SW decoding was done.
        private boolean mDisabledHardwareAcceleration = false;
        private int mPreviousHardwareAccelerationMode;
    
        // Tips
        private View mOverlayTips;
        private static final String PREF_TIPS_SHOWN = "video_player_tips_shown";
    
        // Navigation handling (DVD, Blu-Ray...)
        private ImageButton mNavMenu;
        private boolean mHasMenu = false;
        private boolean mIsNavMenu = false;
    
        @Override
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.i(TAG, "onCreate.");
            if (LibVlcUtil.isJellyBeanMR1OrLater()) {
                // Get the media router service (Miracast)
                mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);
                mMediaRouterCallback = new MediaRouter.SimpleCallback() {
                    @Override
                    public void onRoutePresentationDisplayChanged(
                            MediaRouter router, MediaRouter.RouteInfo info) {
                        Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
                        removePresentation();
                    }
                };
                Log.d(TAG, "MediaRouter information : " + mMediaRouter  .toString());
            }
    
            mSettings = PreferenceManager.getDefaultSharedPreferences(this);
    
            /* Services and miscellaneous */
            mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
            mAudioMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
    
            mEnableCloneMode = mSettings.getBoolean("enable_clone_mode", false);
            createPresentation();
            setContentView(mPresentation == null ? R.layout.player : R.layout.player_remote_control);
    
            if (LibVlcUtil.isICSOrLater())
                getWindow().getDecorView().findViewById(android.R.id.content).setOnSystemUiVisibilityChangeListener(
                        new OnSystemUiVisibilityChangeListener() {
                            @Override
                            public void onSystemUiVisibilityChange(int visibility) {
                                if (visibility == mUiVisibility)
                                    return;
                                setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
                                if (visibility == View.SYSTEM_UI_FLAG_VISIBLE && !mShowing && !isFinishing()) {
                                    showOverlay();
                                }
                                mUiVisibility = visibility;
                            }
                        }
                );
    
            /** initialize Views an their Events */
            mOverlayHeader = findViewById(R.id.player_overlay_header);
            mOverlayOption = findViewById(R.id.option_overlay);
            mOverlayProgress = findViewById(R.id.progress_overlay);
            mOverlayBackground = findViewById(R.id.player_overlay_background);
    
            /* header */
            mTitle = (TextView) findViewById(R.id.player_overlay_title);
            mSysTime = (TextView) findViewById(R.id.player_overlay_systime);
            mBattery = (TextView) findViewById(R.id.player_overlay_battery);
    
            // Position and remaining time
            mTime = (TextView) findViewById(R.id.player_overlay_time);
            mTime.setOnClickListener(mRemainingTimeListener);
            mLength = (TextView) findViewById(R.id.player_overlay_length);
            mLength.setOnClickListener(mRemainingTimeListener);
    
            // the info textView is not on the overlay
            mInfo = (TextView) findViewById(R.id.player_overlay_info);
    
            mEnableBrightnessGesture = mSettings.getBoolean("enable_brightness_gesture", true);
            mScreenOrientation = Integer.valueOf(
                    mSettings.getString("screen_orientation_value", "4" /*SCREEN_ORIENTATION_SENSOR*/));
    
            mEnableJumpButtons = mSettings.getBoolean("enable_jump_buttons", false);
            mPlayPause = (ImageButton) findViewById(R.id.player_overlay_play);
            mPlayPause.setOnClickListener(mPlayPauseListener);
            mBackward = (ImageButton) findViewById(R.id.player_overlay_backward);
            mBackward.setOnClickListener(mBackwardListener);
            mForward = (ImageButton) findViewById(R.id.player_overlay_forward);
            mForward.setOnClickListener(mForwardListener);
    
            mAudioTrack = (ImageButton) findViewById(R.id.player_overlay_audio);
            mAudioTrack.setVisibility(View.GONE);
            mSubtitle = (ImageButton) findViewById(R.id.player_overlay_subtitle);
            mSubtitle.setVisibility(View.GONE);
            mNavMenu = (ImageButton) findViewById(R.id.player_overlay_navmenu);
            mNavMenu.setVisibility(View.GONE);
    
            mLock = (ImageButton) findViewById(R.id.lock_overlay_button);
            mLock.setOnClickListener(mLockListener);
    
            mSize = (ImageButton) findViewById(R.id.player_overlay_size);
            mSize.setOnClickListener(mSizeListener);
    
            mMenu = (ImageButton) findViewById(R.id.player_overlay_adv_function);
    
            try {
                mLibVLC = VLCInstance.getLibVlcInstance();
            } catch (LibVlcException e) {
                Log.d(TAG, "LibVLC initialisation failed");
                return;
            }
    
            mSurface = (SurfaceView) findViewById(R.id.player_surface);
            mSurfaceHolder = mSurface.getHolder();
            mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);
            String chroma = mSettings.getString("chroma_format", "");
            if(LibVlcUtil.isGingerbreadOrLater() && chroma.equals("YV12")) {
                mSurfaceHolder.setFormat(ImageFormat.YV12);
            } else if (chroma.equals("RV16")) {
                mSurfaceHolder.setFormat(PixelFormat.RGB_565);
            } else {
                mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
            }
    
            mSubtitlesSurface = (SurfaceView) findViewById(R.id.subtitles_surface);
            mSubtitlesSurfaceHolder = mSubtitlesSurface.getHolder();
            mSubtitlesSurfaceHolder.setFormat(PixelFormat.RGBA_8888);
            mSubtitlesSurface.setZOrderMediaOverlay(true);
            if (mPresentation == null) {
                mSurfaceHolder.addCallback(mSurfaceCallback);
                mSubtitlesSurfaceHolder.addCallback(mSubtitlesSurfaceCallback);
            }
    
            mSeekbar = (SeekBar) findViewById(R.id.player_overlay_seekbar);
            mSeekbar.setOnSeekBarChangeListener(mSeekListener);
    
            /* Loading view */
            mLoading = (ImageView) findViewById(R.id.player_overlay_loading);
            mLoadingText = (TextView) findViewById(R.id.player_overlay_loading_text);
            startLoadingAnimation();
    
            mSwitchingView = false;
            mEndReached = false;
    
            // Clear the resume time, since it is only used for resumes in external
            // videos.
            SharedPreferences.Editor editor = mSettings.edit();
            editor.putLong(PreferencesActivity.VIDEO_RESUME_TIME, -1);
            // Also clear the subs list, because it is supposed to be per session
            // only (like desktop VLC). We don't want the customs subtitle file
            // to persist forever with this video.
            editor.putString(PreferencesActivity.VIDEO_SUBTITLE_FILES, null);
            editor.commit();
    
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
            filter.addAction(VLCApplication.SLEEP_INTENT);
            registerReceiver(mReceiver, filter);
    
            Log.d(TAG,
                    "Hardware acceleration mode: "
                            + Integer.toString(mLibVLC.getHardwareAcceleration()));
    
            /* Only show the subtitles surface when using "Full Acceleration" mode */
            if (mLibVLC.getHardwareAcceleration() == LibVLC.HW_ACCELERATION_FULL)
                mSubtitlesSurface.setVisibility(View.VISIBLE);
            // Signal to LibVLC that the videoPlayerActivity was created, thus the
            // SurfaceView is now available for MediaCodec direct rendering.
            mLibVLC.eventVideoPlayerActivityCreated(true);
            //mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);
            EventHandler em = EventHandler.getInstance();
            em.addHandler(eventHandler);
    
            this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
    
            // Extra initialization when no secondary display is detected
            if (mPresentation == null) {
                // Orientation
                // 100 is the value for screen_orientation_start_lock
                setRequestedOrientation(mScreenOrientation != 100
                        ? mScreenOrientation
                        : getScreenOrientation());
                // Tips
                mOverlayTips = findViewById(R.id.player_overlay_tips);
                if(mSettings.getBoolean(PREF_TIPS_SHOWN, false))
                    mOverlayTips.setVisibility(View.GONE);
                else {
                    mOverlayTips.bringToFront();
                    mOverlayTips.invalidate();
                }
            } else
                setRequestedOrientation(getScreenOrientation());
    
            updateNavStatus();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.i(TAG, "onPause. mSwitchingView="+mSwitchingView);
            if (mMediaRouter != null) {
                // Stop listening for changes to media routes.
                mediaRouterAddCallback(false);
            }
    
            if(mSwitchingView) {
                Log.d(TAG, "mLocation = \"" + mLocation + "\"");
                AudioServiceController.getInstance().showWithoutParse(savedIndexPosition);
                AudioServiceController.getInstance().unbindAudioService(this);
                return;
            }
    
            long time = mLibVLC.getTime();
            long length = mLibVLC.getLength();
            //remove saved position if in the last 5 seconds
            if (length - time < 5000)
                time = 0;
            else
                time -= 5000; // go back 5 seconds, to compensate loading time
    
            /*
             * Pausing here generates errors because the vout is constantly
             * trying to refresh itself every 80ms while the surface is not
             * accessible anymore.
             * To workaround that, we keep the last known position in the playlist
             * in savedIndexPosition to be able to restore it during onResume().
             */
            mLibVLC.stop();
    
            mSurface.setKeepScreenOn(false);
    
            SharedPreferences.Editor editor = mSettings.edit();
            // Save position
            if (time >= 0 && mCanSeek) {
                if(MediaDatabase.getInstance().mediaItemExists(mLocation)) {
                    MediaDatabase.getInstance().updateMedia(
                            mLocation,
                            MediaDatabase.mediaColumn.MEDIA_TIME,
                            time);
                } else {
                    // Video file not in media library, store time just for onResume()
                    editor.putLong(PreferencesActivity.VIDEO_RESUME_TIME, time);
                }
            }
            // Save selected subtitles
            String subtitleList_serialized = null;
            if(mSubtitleSelectedFiles.size() > 0) {
                Log.d(TAG, "Saving selected subtitle files");
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                try {
                    ObjectOutputStream oos = new ObjectOutputStream(bos);
                    oos.writeObject(mSubtitleSelectedFiles);
                    subtitleList_serialized = bos.toString();
                } catch(IOException e) {}
            }
            editor.putString(PreferencesActivity.VIDEO_SUBTITLE_FILES, subtitleList_serialized);
    
            editor.commit();
            AudioServiceController.getInstance().unbindAudioService(this);
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        @Override
        protected void onStop() {
            super.onStop();
            Log.i(TAG, "onStop.");
            // Dismiss the presentation when the activity is not visible.
            if (mPresentation != null) {
                Log.i(TAG, "Dismissing presentation because the activity is no longer visible.");
                mPresentation.dismiss();
                mPresentation = null;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.i(TAG, "onDestroy.");
            unregisterReceiver(mReceiver);
    
            EventHandler em = EventHandler.getInstance();
            em.removeHandler(eventHandler);
    
            // MediaCodec opaque direct rendering should not be used anymore since there is no surface to attach.
            mLibVLC.eventVideoPlayerActivityCreated(false);
            // HW acceleration was temporarily disabled because of an error, restore the previous value.
            if (mDisabledHardwareAcceleration)
                mLibVLC.setHardwareAcceleration(mPreviousHardwareAccelerationMode);
    
            mAudioManager = null;
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.i(TAG, "onResume.");
            
            mSwitchingView = false;
            AudioServiceController.getInstance().bindAudioService(this,
                    new AudioServiceController.AudioServiceConnectionListener() {
                @Override
                public void onConnectionSuccess() {
                    mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_SUCCESS);
                }
    
                @Override
                public void onConnectionFailed() {
                    mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_FAILED);
                }
            });
    
            if (mMediaRouter != null) {
                // Listen for changes to media routes.
                mediaRouterAddCallback(true);
            }
        }
    
        /**
         * Add or remove MediaRouter callbacks. This is provided for version targeting.
         *
         * @param add true to add, false to remove
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private void mediaRouterAddCallback(boolean add) {
            if(!LibVlcUtil.isJellyBeanMR1OrLater() || mMediaRouter == null) return;
    
            if(add)
                mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mMediaRouterCallback);
            else
                mMediaRouter.removeCallback(mMediaRouterCallback);
        }
    
        private void startPlayback() {
        	 Log.i(TAG, "startPlayback.");
             
        	
            loadMedia();
    
            /*
             * if the activity has been paused by pressing the power button,
             * pressing it again will show the lock screen.
             * But onResume will also be called, even if vlc-android is still in the background.
             * To workaround that, pause playback if the lockscreen is displayed
             */
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (mLibVLC != null && mLibVLC.isPlaying()) {
                        KeyguardManager km = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);
                        if (km.inKeyguardRestrictedInputMode())
                            mLibVLC.pause();
                    }
                }}, 500);
    
            // Add any selected subtitle file from the file picker
            if(mSubtitleSelectedFiles.size() > 0) {
                for(String file : mSubtitleSelectedFiles) {
                    Log.i(TAG, "Adding user-selected subtitle " + file);
                    mLibVLC.addSubtitleTrack(file);
                }
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if(data == null) return;
    
            if(data.getDataString() == null) {
                Log.d(TAG, "Subtitle selection dialog was cancelled");
            }
            if(data.getData() == null) return;
    
            String subtitlePath = data.getData().getPath();
            if(requestCode == CommonDialogs.INTENT_SPECIFIC) {
                Log.d(TAG, "Specific subtitle file: " + subtitlePath);
            } else if(requestCode == CommonDialogs.INTENT_GENERIC) {
                Log.d(TAG, "Generic subtitle file: " + subtitlePath);
            }
            mSubtitleSelectedFiles.add(subtitlePath);
        }
    
        public static void start(Context context, String location) {
            start(context, location, null, -1, false, false);
        }
    
        public static void start(Context context, String location, Boolean fromStart) {
            start(context, location, null, -1, false, fromStart);
        }
    
        public static void start(Context context, String location, String title, Boolean dontParse) {
            start(context, location, title, -1, dontParse, false);
        }
    
        public static void start(Context context, String location, String title, int position, Boolean dontParse) {
            start(context, location, title, position, dontParse, false);
        }
    
        public static void start(Context context, String location, String title, int position, Boolean dontParse, Boolean fromStart) {
            Intent intent = new Intent(context, VideoPlayerActivity.class);
            intent.setAction(VideoPlayerActivity.PLAY_FROM_VIDEOGRID);
            intent.putExtra("itemLocation", location);
            intent.putExtra("itemTitle", title);
            intent.putExtra("dontParse", dontParse);
            intent.putExtra("fromStart", fromStart);
            intent.putExtra("itemPosition", position);
    
            if (dontParse)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    
            context.startActivity(intent);
        }
    
        private final BroadcastReceiver mReceiver = new BroadcastReceiver()
        {
            @Override
            public void onReceive(Context context, Intent intent)
            {
                String action = intent.getAction();
                if (action.equalsIgnoreCase(Intent.ACTION_BATTERY_CHANGED)) {
                    int batteryLevel = intent.getIntExtra("level", 0);
                    if (batteryLevel >= 50)
                        mBattery.setTextColor(Color.GREEN);
                    else if (batteryLevel >= 30)
                        mBattery.setTextColor(Color.YELLOW);
                    else
                        mBattery.setTextColor(Color.RED);
                    mBattery.setText(String.format("%d%%", batteryLevel));
                }
                else if (action.equalsIgnoreCase(VLCApplication.SLEEP_INTENT)) {
                    finish();
                }
            }
        };
    
        @Override
        public boolean onTrackballEvent(MotionEvent event) {
            showOverlay();
            return true;
        }
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
            super.onConfigurationChanged(newConfig);
        }
    
        @Override
        public void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {
            if (width * height == 0)
                return;
    
            // store video size
            mVideoHeight = height;
            mVideoWidth = width;
            mVideoVisibleHeight = visible_height;
            mVideoVisibleWidth  = visible_width;
            mSarNum = sar_num;
            mSarDen = sar_den;
            Message msg = mHandler.obtainMessage(SURFACE_SIZE);
            mHandler.sendMessage(msg);
        }
    
        /**
         * Lock screen rotation
         */
        private void lockScreen() {
            if(mScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
                    setRequestedOrientation(14 /* SCREEN_ORIENTATION_LOCKED */);
                else
                    setRequestedOrientation(getScreenOrientation());
            }
            showInfo(R.string.locked, 1000);
            mLock.setBackgroundResource(R.drawable.ic_locked);
            mTime.setEnabled(false);
            mSeekbar.setEnabled(false);
            mLength.setEnabled(false);
            hideOverlay(true);
        }
    
        /**
         * Remove screen lock
         */
        private void unlockScreen() {
            if(mScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR)
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
            showInfo(R.string.unlocked, 1000);
            mLock.setBackgroundResource(R.drawable.ic_lock);
            mTime.setEnabled(true);
            mSeekbar.setEnabled(true);
            mLength.setEnabled(true);
            mShowing = false;
            showOverlay();
        }
    
        /**
         * Show text in the info view for "duration" milliseconds
         * @param text
         * @param duration
         */
        private void showInfo(String text, int duration) {
            mInfo.setVisibility(View.VISIBLE);
            mInfo.setText(text);
            mHandler.removeMessages(FADE_OUT_INFO);
            mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, duration);
        }
    
        private void showInfo(int textid, int duration) {
            mInfo.setVisibility(View.VISIBLE);
            mInfo.setText(textid);
            mHandler.removeMessages(FADE_OUT_INFO);
            mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, duration);
        }
    
        /**
         * Show text in the info view
         * @param text
         */
        private void showInfo(String text) {
            mInfo.setVisibility(View.VISIBLE);
            mInfo.setText(text);
            mHandler.removeMessages(FADE_OUT_INFO);
        }
    
        /**
         * hide the info view with "delay" milliseconds delay
         * @param delay
         */
        private void hideInfo(int delay) {
            mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, delay);
        }
    
        /**
         * hide the info view
         */
        private void hideInfo() {
            hideInfo(0);
        }
    
        private void fadeOutInfo() {
            if (mInfo.getVisibility() == View.VISIBLE)
                mInfo.startAnimation(AnimationUtils.loadAnimation(
                        VideoPlayerActivity.this, android.R.anim.fade_out));
            mInfo.setVisibility(View.INVISIBLE);
        }
    
        @TargetApi(Build.VERSION_CODES.FROYO)
        private int changeAudioFocus(boolean acquire) {
            if(!LibVlcUtil.isFroyoOrLater()) // NOP if not supported
                return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
    
            if (mAudioFocusListener == null) {
                mAudioFocusListener = new OnAudioFocusChangeListener() {
                    @Override
                    public void onAudioFocusChange(int focusChange) {
                        /*
                         * Pause playback during alerts and notifications
                         */
                        switch (focusChange)
                        {
                            case AudioManager.AUDIOFOCUS_LOSS:
                            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                                if (mLibVLC.isPlaying())
                                    mLibVLC.pause();
                                break;
                            case AudioManager.AUDIOFOCUS_GAIN:
                            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
                            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
                                if (!mLibVLC.isPlaying())
                                    mLibVLC.play();
                                break;
                        }
                    }
                };
            }
    
            int result;
            if(acquire) {
                result = mAudioManager.requestAudioFocus(mAudioFocusListener,
                        AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
                mAudioManager.setParameters("bgm_state=true");
            }
            else {
                if (mAudioManager != null) {
                    result = mAudioManager.abandonAudioFocus(mAudioFocusListener);
                    mAudioManager.setParameters("bgm_state=false");
                }
                else
                    result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            }
    
            return result;
        }
    
        /**
         *  Handle libvlc asynchronous events
         */
        private final Handler eventHandler = new VideoPlayerEventHandler(this);
    
        private static class VideoPlayerEventHandler extends WeakHandler {
            public VideoPlayerEventHandler(VideoPlayerActivity owner) {
                super(owner);
            }
    
            @Override
            public void handleMessage(Message msg) {
                VideoPlayerActivity activity = getOwner();
                if(activity == null) return;
                // Do not handle events if we are leaving the VideoPlayerActivity
                if (activity.mSwitchingView) return;
    
                switch (msg.getData().getInt("event")) {
                    case EventHandler.MediaParsedChanged:
                        Log.i(TAG, "MediaParsedChanged");
                        activity.updateNavStatus();
                        if (!activity.mHasMenu && activity.mLibVLC.getVideoTracksCount() < 1) {
                            Log.i(TAG, "No video track, open in audio mode");
                            activity.switchToAudioMode();
                        }
                        break;
                    case EventHandler.MediaPlayerPlaying:
                        Log.i(TAG, "MediaPlayerPlaying");
                        activity.stopLoadingAnimation();
                        activity.showOverlay();
                        /** FIXME: update the track list when it changes during the
                         *  playback. (#7540) */
                        activity.setESTrackLists(true);
                        activity.setESTracks();
                        activity.changeAudioFocus(true);
                        activity.updateNavStatus();
                        break;
                    case EventHandler.MediaPlayerPaused:
                        Log.i(TAG, "MediaPlayerPaused");
                        break;
                    case EventHandler.MediaPlayerStopped:
                        Log.i(TAG, "MediaPlayerStopped");
                        activity.changeAudioFocus(false);
                        break;
                    case EventHandler.MediaPlayerEndReached:
                        Log.i(TAG, "MediaPlayerEndReached");
                        activity.changeAudioFocus(false);
                        activity.endReached();
                        break;
                    case EventHandler.MediaPlayerVout:
                        activity.updateNavStatus();
                        if (!activity.mHasMenu)
                            activity.handleVout(msg);
                        break;
                    case EventHandler.MediaPlayerPositionChanged:
                        if (!activity.mCanSeek)
                            activity.mCanSeek = true;
                        //don't spam the logs
                        break;
                    case EventHandler.MediaPlayerEncounteredError:
                        Log.i(TAG, "MediaPlayerEncounteredError");
                        activity.encounteredError();
                        break;
                    case EventHandler.HardwareAccelerationError:
                        Log.i(TAG, "HardwareAccelerationError");
                        activity.handleHardwareAccelerationError();
                        break;
                    case EventHandler.MediaPlayerTimeChanged:
                        // avoid useless error logs
                        break;
                    default:
                        Log.e(TAG, String.format("Event not handled (0x%x)", msg.getData().getInt("event")));
                        break;
                }
                activity.updateOverlayPausePlay();
            }
        };
    
        /**
         * Handle resize of the surface and the overlay
         */
        private final Handler mHandler = new VideoPlayerHandler(this);
    
        private static class VideoPlayerHandler extends WeakHandler {
            public VideoPlayerHandler(VideoPlayerActivity owner) {
                super(owner);
            }
    
            @Override
            public void handleMessage(Message msg) {
                VideoPlayerActivity activity = getOwner();
                if(activity == null) // WeakReference could be GC'ed early
                    return;
    
                switch (msg.what) {
                    case FADE_OUT:
                        activity.hideOverlay(false);
                        break;
                    case SHOW_PROGRESS:
                        int pos = activity.setOverlayProgress();
                        if (activity.canShowProgress()) {
                            msg = obtainMessage(SHOW_PROGRESS);
                            sendMessageDelayed(msg, 1000 - (pos % 1000));
                        }
                        break;
                    case SURFACE_SIZE:
                        activity.changeSurfaceSize();
                        break;
                    case FADE_OUT_INFO:
                        activity.fadeOutInfo();
                        break;
                    case AUDIO_SERVICE_CONNECTION_SUCCESS:
                        activity.startPlayback();
                        break;
                    case AUDIO_SERVICE_CONNECTION_FAILED:
                        activity.finish();
                        break;
                }
            }
        };
    
        private boolean canShowProgress() {
            return !mDragging && mShowing && mLibVLC.isPlaying();
        }
    
        private void endReached() {
            if(mLibVLC.getMediaList().expandMedia(savedIndexPosition) == 0) {
                Log.d(TAG, "Found a video playlist, expanding it");
                eventHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        loadMedia();
                    }
                }, 1000);
            } else {
                /* Exit player when reaching the end */
                mEndReached = true;
                finish();
            }
        }
    
        private void encounteredError() {
            /* Encountered Error, exit player with a message */
            AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)
            .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int id) {
                    finish();
                }
            })
            .setTitle(R.string.encountered_error_title)
            .setMessage(R.string.encountered_error_message)
            .create();
            dialog.show();
        }
    
        public void eventHardwareAccelerationError() {
            EventHandler em = EventHandler.getInstance();
            em.callback(EventHandler.HardwareAccelerationError, new Bundle());
        }
    
        private void handleHardwareAccelerationError() {
            mLibVLC.stop();
            AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)
            .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int id) {
                    mDisabledHardwareAcceleration = true;
                    mPreviousHardwareAccelerationMode = mLibVLC.getHardwareAcceleration();
                    mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);
                    mSubtitlesSurface.setVisibility(View.INVISIBLE);
                    loadMedia();
                }
            })
            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int id) {
                    finish();
                }
            })
            .setTitle(R.string.hardware_acceleration_error_title)
            .setMessage(R.string.hardware_acceleration_error_message)
            .create();
            if(!isFinishing())
                dialog.show();
        }
    
        private void handleVout(Message msg) {
            if (msg.getData().getInt("data") == 0 && !mEndReached) {
                /* Video track lost, open in audio mode */
                Log.i(TAG, "Video track lost, switching to audio");
                mSwitchingView = true;
                finish();
            }
        }
    
        private void switchToAudioMode() {
        
        	
            mSwitchingView = true;
            // Show the MainActivity if it is not in background.
            if (getIntent().getAction() != null
                && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
                Intent i = new Intent(this, MainActivity.class);
                startActivity(i);
            }
            finish();
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private void changeSurfaceSize() {
            int sw;
            int sh;
    
            // get screen size
            if (mPresentation == null) {
                sw = getWindow().getDecorView().getWidth();
                sh = getWindow().getDecorView().getHeight();
            } else {
                sw = mPresentation.getWindow().getDecorView().getWidth();
                sh = mPresentation.getWindow().getDecorView().getHeight();
            }
    
            double dw = sw, dh = sh;
            boolean isPortrait;
    
            if (mPresentation == null) {
                // getWindow().getDecorView() doesn't always take orientation into account, we have to correct the values
                isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
            } else {
                isPortrait = false;
            }
    
            if (sw > sh && isPortrait || sw < sh && !isPortrait) {
                dw = sh;
                dh = sw;
            }
    
            // sanity check
            if (dw * dh == 0 || mVideoWidth * mVideoHeight == 0) {
                Log.e(TAG, "Invalid surface size");
                return;
            }
    
            // compute the aspect ratio
            double ar, vw;
            if (mSarDen == mSarNum) {
                /* No indication about the density, assuming 1:1 */
                vw = mVideoVisibleWidth;
                ar = (double)mVideoVisibleWidth / (double)mVideoVisibleHeight;
            } else {
                /* Use the specified aspect ratio */
                vw = mVideoVisibleWidth * (double)mSarNum / mSarDen;
                ar = vw / mVideoVisibleHeight;
            }
    
            // compute the display aspect ratio
            double dar = dw / dh;
    
            switch (mCurrentSize) {
                case SURFACE_BEST_FIT:
                    if (dar < ar)
                        dh = dw / ar;
                    else
                        dw = dh * ar;
                    break;
                case SURFACE_FIT_HORIZONTAL:
                    dh = dw / ar;
                    break;
                case SURFACE_FIT_VERTICAL:
                    dw = dh * ar;
                    break;
                case SURFACE_FILL:
                    break;
                case SURFACE_16_9:
                    ar = 16.0 / 9.0;
                    if (dar < ar)
                        dh = dw / ar;
                    else
                        dw = dh * ar;
                    break;
                case SURFACE_4_3:
                    ar = 4.0 / 3.0;
                    if (dar < ar)
                        dh = dw / ar;
                    else
                        dw = dh * ar;
                    break;
                case SURFACE_ORIGINAL:
                    dh = mVideoVisibleHeight;
                    dw = vw;
                    break;
            }
    
            SurfaceView surface;
            SurfaceView subtitlesSurface;
            SurfaceHolder surfaceHolder;
            SurfaceHolder subtitlesSurfaceHolder;
            FrameLayout surfaceFrame;
    
            if (mPresentation == null) {
                surface = mSurface;
                subtitlesSurface = mSubtitlesSurface;
                surfaceHolder = mSurfaceHolder;
                subtitlesSurfaceHolder = mSubtitlesSurfaceHolder;
                surfaceFrame = mSurfaceFrame;
            } else {
                surface = mPresentation.mSurface;
                subtitlesSurface = mPresentation.mSubtitlesSurface;
                surfaceHolder = mPresentation.mSurfaceHolder;
                subtitlesSurfaceHolder = mPresentation.mSubtitlesSurfaceHolder;
                surfaceFrame = mPresentation.mSurfaceFrame;
            }
    
            // force surface buffer size
            surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
            subtitlesSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
    
            // set display size
            LayoutParams lp = surface.getLayoutParams();
            lp.width  = (int) Math.ceil(dw * mVideoWidth / mVideoVisibleWidth);
            lp.height = (int) Math.ceil(dh * mVideoHeight / mVideoVisibleHeight);
            surface.setLayoutParams(lp);
            subtitlesSurface.setLayoutParams(lp);
    
            // set frame size (crop if necessary)
            lp = surfaceFrame.getLayoutParams();
            lp.width = (int) Math.floor(dw);
            lp.height = (int) Math.floor(dh);
            surfaceFrame.setLayoutParams(lp);
    
            surface.invalidate();
            subtitlesSurface.invalidate();
        }
    
        /**
         * show/hide the overlay
         */
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (mIsLocked) {
                // locked, only handle show/hide & ignore all actions
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (!mShowing) {
                        showOverlay();
                    } else {
                        hideOverlay(true);
                    }
                }
                return false;
            }
    
            DisplayMetrics screen = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(screen);
    
            if (mSurfaceYDisplayRange == 0)
                mSurfaceYDisplayRange = Math.min(screen.widthPixels, screen.heightPixels);
    
            float y_changed = event.getRawY() - mTouchY;
            float x_changed = event.getRawX() - mTouchX;
    
            // coef is the gradient's move to determine a neutral zone
            float coef = Math.abs (y_changed / x_changed);
            float xgesturesize = ((x_changed / screen.xdpi) * 2.54f);
    
            /* Offset for Mouse Events */
            int[] offset = new int[2];
            mSurface.getLocationOnScreen(offset);
            int xTouch = Math.round((event.getRawX() - offset[0]) * mVideoWidth / mSurface.getWidth());
            int yTouch = Math.round((event.getRawY() - offset[1]) * mVideoHeight / mSurface.getHeight());
    
            switch (event.getAction()) {
    
            case MotionEvent.ACTION_DOWN:
                // Audio
                mTouchY = event.getRawY();
                mVol = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                mTouchAction = TOUCH_NONE;
                // Seek
                mTouchX = event.getRawX();
                // Mouse events for the core
                LibVLC.sendMouseEvent(MotionEvent.ACTION_DOWN, 0, xTouch, yTouch);
                break;
    
            case MotionEvent.ACTION_MOVE:
                // Mouse events for the core
                LibVLC.sendMouseEvent(MotionEvent.ACTION_MOVE, 0, xTouch, yTouch);
    
                // No volume/brightness action if coef < 2 or a secondary display is connected
                //TODO : Volume action when a secondary display is connected
                if (coef > 2 && mPresentation == null) {
                    // Volume (Up or Down - Right side)
                    if (!mEnableBrightnessGesture || (int)mTouchX > (screen.widthPixels / 2)){
                        doVolumeTouch(y_changed);
                    }
                    // Brightness (Up or Down - Left side)
                    if (mEnableBrightnessGesture && (int)mTouchX < (screen.widthPixels / 2)){
                        doBrightnessTouch(y_changed);
                    }
                    // Extend the overlay for a little while, so that it doesn't
                    // disappear on the user if more adjustment is needed. This
                    // is because on devices with soft navigation (e.g. Galaxy
                    // Nexus), gestures can't be made without activating the UI.
                    if(AndroidDevices.hasNavBar())
                        showOverlay();
                }
                // Seek (Right or Left move)
                doSeekTouch(coef, xgesturesize, false);
                break;
    
            case MotionEvent.ACTION_UP:
                // Mouse events for the core
                LibVLC.sendMouseEvent(MotionEvent.ACTION_UP, 0, xTouch, yTouch);
    
                // Audio or Brightness
                if ( mTouchAction == TOUCH_NONE) {
                    if (!mShowing) {
                        showOverlay();
                    } else {
                        hideOverlay(true);
                    }
                }
                // Seek
                doSeekTouch(coef, xgesturesize, true);
                break;
            }
            return mTouchAction != TOUCH_NONE;
        }
    
        private void doSeekTouch(float coef, float gesturesize, boolean seek) {
            // No seek action if coef > 0.5 and gesturesize < 1cm
            if (coef > 0.5 || Math.abs(gesturesize) < 1 || !mCanSeek)
                return;
    
            if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_SEEK)
                return;
            mTouchAction = TOUCH_SEEK;
    
            // Always show seekbar when searching
            if (!mShowing) showOverlay();
    
            long length = mLibVLC.getLength();
            long time = mLibVLC.getTime();
    
            // Size of the jump, 10 minutes max (600000), with a bi-cubic progression, for a 8cm gesture
            int jump = (int) (Math.signum(gesturesize) * ((600000 * Math.pow((gesturesize / 8), 4)) + 3000));
    
            // Adjust the jump
            if ((jump > 0) && ((time + jump) > length))
                jump = (int) (length - time);
            if ((jump < 0) && ((time + jump) < 0))
                jump = (int) -time;
    
            //Jump !
            if (seek && length > 0)
                mLibVLC.setTime(time + jump);
    
            if (length > 0)
                //Show the jump's size
                showInfo(String.format("%s%s (%s)",
                        jump >= 0 ? "+" : "",
                        Strings.millisToString(jump),
                        Strings.millisToString(time + jump)), 1000);
            else
                showInfo(R.string.unseekable_stream, 1000);
        }
    
        private void doVolumeTouch(float y_changed) {
            if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_VOLUME)
                return;
            int delta = -(int) ((y_changed / mSurfaceYDisplayRange) * mAudioMax);
            int vol = (int) Math.min(Math.max(mVol + delta, 0), mAudioMax);
            if (delta != 0) {
                mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, vol, 0);
                mTouchAction = TOUCH_VOLUME;
                showInfo(getString(R.string.volume) + '\u00A0' + Integer.toString(vol),1000);
            }
        }
    
        private void initBrightnessTouch() {
            float brightnesstemp = 0.01f;
            // Initialize the layoutParams screen brightness
            try {
                brightnesstemp = android.provider.Settings.System.getInt(getContentResolver(),
                        android.provider.Settings.System.SCREEN_BRIGHTNESS) / 255.0f;
            } catch (SettingNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            WindowManager.LayoutParams lp = getWindow().getAttributes();
            lp.screenBrightness = brightnesstemp;
            getWindow().setAttributes(lp);
            mIsFirstBrightnessGesture = false;
        }
    
        private void doBrightnessTouch(float y_changed) {
            if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_BRIGHTNESS)
                return;
            if (mIsFirstBrightnessGesture) initBrightnessTouch();
            mTouchAction = TOUCH_BRIGHTNESS;
    
            // Set delta : 0.07f is arbitrary for now, it possibly will change in the future
            float delta = - y_changed / mSurfaceYDisplayRange * 0.07f;
    
            // Estimate and adjust Brightness
            WindowManager.LayoutParams lp = getWindow().getAttributes();
            lp.screenBrightness =  Math.min(Math.max(lp.screenBrightness + delta, 0.01f), 1);
    
            // Set Brightness
            getWindow().setAttributes(lp);
            showInfo(getString(R.string.brightness) + '\u00A0' + Math.round(lp.screenBrightness*15),1000);
        }
    
        /**
         * handle changes of the seekbar (slicer)
         */
        private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
    
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                mDragging = true;
                showOverlay(OVERLAY_INFINITE);
            }
    
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                mDragging = false;
                showOverlay();
                hideInfo();
            }
    
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser && mCanSeek) {
                    mLibVLC.setTime(progress);
                    setOverlayProgress();
                    mTime.setText(Strings.millisToString(progress));
                    showInfo(Strings.millisToString(progress));
                }
    
            }
        };
    
        /**
        *
        */
        private final OnClickListener mAudioTrackListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                final String[] arrList = new String[mAudioTracksList.size()];
                int i = 0;
                int listPosition = 0;
                for(Map.Entry entry : mAudioTracksList.entrySet()) {
                    arrList[i] = entry.getValue();
                    // map the track position to the list position
                    if(entry.getKey() == mLibVLC.getAudioTrack())
                        listPosition = i;
                    i++;
                }
                AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)
                .setTitle(R.string.track_audio)
                .setSingleChoiceItems(arrList, listPosition, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int listPosition) {
                        int trackID = -1;
                        // Reverse map search...
                        for(Map.Entry entry : mAudioTracksList.entrySet()) {
                            if(arrList[listPosition].equals(entry.getValue())) {
                                trackID = entry.getKey();
                                break;
                            }
                        }
                        if(trackID < 0) return;
    
                        MediaDatabase.getInstance().updateMedia(
                                mLocation,
                                MediaDatabase.mediaColumn.MEDIA_AUDIOTRACK,
                                trackID);
                        mLibVLC.setAudioTrack(trackID);
                        dialog.dismiss();
                    }
                })
                .create();
                dialog.setCanceledOnTouchOutside(true);
                dialog.setOwnerActivity(VideoPlayerActivity.this);
                dialog.show();
            }
        };
    
        /**
        *
        */
        private final OnClickListener mSubtitlesListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                final String[] arrList = new String[mSubtitleTracksList.size()];
                int i = 0;
                int listPosition = 0;
                for(Map.Entry entry : mSubtitleTracksList.entrySet()) {
                    arrList[i] = entry.getValue();
                    // map the track position to the list position
                    if(entry.getKey() == mLibVLC.getSpuTrack())
                        listPosition = i;
                    i++;
                }
    
                AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)
                .setTitle(R.string.track_text)
                .setSingleChoiceItems(arrList, listPosition, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int listPosition) {
                        int trackID = -2;
                        // Reverse map search...
                        for(Map.Entry entry : mSubtitleTracksList.entrySet()) {
                            if(arrList[listPosition].equals(entry.getValue())) {
                                trackID = entry.getKey();
                                break;
                            }
                        }
                        if(trackID < -1) return;
    
                        MediaDatabase.getInstance().updateMedia(
                                mLocation,
                                MediaDatabase.mediaColumn.MEDIA_SPUTRACK,
                                trackID);
                        mLibVLC.setSpuTrack(trackID);
                        dialog.dismiss();
                    }
                })
                .create();
                dialog.setCanceledOnTouchOutside(true);
                dialog.setOwnerActivity(VideoPlayerActivity.this);
                dialog.show();
            }
        };
    
        private final OnClickListener mNavMenuListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                /* Try to return to the menu. */
                /* FIXME: not working correctly in all cases */
                mLibVLC.setTitle(0);
            }
        };
    
        /**
        *
        */
        private final OnClickListener mPlayPauseListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mLibVLC.isPlaying())
                    pause();
                else
                    play();
                showOverlay();
            }
        };
    
        /**
        *
        */
        private final OnClickListener mBackwardListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                seek(-10000);
            }
        };
    
        /**
        *
        */
        private final OnClickListener mForwardListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                seek(10000);
            }
        };
    
        public void seek(int delta) {
            // unseekable stream
            if(mLibVLC.getLength() <= 0 || !mCanSeek) return;
    
            long position = mLibVLC.getTime() + delta;
            if (position < 0) position = 0;
            mLibVLC.setTime(position);
            showOverlay();
        }
    
        /**
         *
         */
        private final OnClickListener mLockListener = new OnClickListener() {
    
            @Override
            public void onClick(View v) {
                if (mIsLocked) {
                    mIsLocked = false;
                    unlockScreen();
                } else {
                    mIsLocked = true;
                    lockScreen();
                }
            }
        };
    
        /**
         *
         */
        private final OnClickListener mSizeListener = new OnClickListener() {
    
            @Override
            public void onClick(View v) {
    
                if (mCurrentSize < SURFACE_ORIGINAL) {
                    mCurrentSize++;
                } else {
                    mCurrentSize = 0;
                }
                changeSurfaceSize();
                switch (mCurrentSize) {
                    case SURFACE_BEST_FIT:
                        showInfo(R.string.surface_best_fit, 1000);
                        break;
                    case SURFACE_FIT_HORIZONTAL:
                        showInfo(R.string.surface_fit_horizontal, 1000);
                        break;
                    case SURFACE_FIT_VERTICAL:
                        showInfo(R.string.surface_fit_vertical, 1000);
                        break;
                    case SURFACE_FILL:
                        showInfo(R.string.surface_fill, 1000);
                        break;
                    case SURFACE_16_9:
                        showInfo("16:9", 1000);
                        break;
                    case SURFACE_4_3:
                        showInfo("4:3", 1000);
                        break;
                    case SURFACE_ORIGINAL:
                        showInfo(R.string.surface_original, 1000);
                        break;
                }
                showOverlay();
            }
        };
    
        private final OnClickListener mRemainingTimeListener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                mDisplayRemainingTime = !mDisplayRemainingTime;
                showOverlay();
            }
        };
    
        /**
         * attach and disattach surface to the lib
         */
        private final SurfaceHolder.Callback mSurfaceCallback = new Callback() {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                if(format == PixelFormat.RGBX_8888)
                    Log.d(TAG, "Pixel format is RGBX_8888");
                else if(format == PixelFormat.RGB_565)
                    Log.d(TAG, "Pixel format is RGB_565");
                else if(format == ImageFormat.YV12)
                    Log.d(TAG, "Pixel format is YV12");
                else
                    Log.d(TAG, "Pixel format is other/unknown");
                if(mLibVLC != null)
                    mLibVLC.attachSurface(holder.getSurface(), VideoPlayerActivity.this);
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if(mLibVLC != null)
                    mLibVLC.detachSurface();
            }
        };
    
        private final SurfaceHolder.Callback mSubtitlesSurfaceCallback = new Callback() {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                if(mLibVLC != null)
                    mLibVLC.attachSubtitlesSurface(holder.getSurface());
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if(mLibVLC != null)
                    mLibVLC.detachSubtitlesSurface();
            }
        };
    
        /**
         * show overlay the the default timeout
         */
        private void showOverlay() {
            showOverlay(OVERLAY_TIMEOUT);
        }
    
        /**
         * show overlay
         */
        private void showOverlay(int timeout) {
            if (mIsNavMenu)
                return;
            mHandler.sendEmptyMessage(SHOW_PROGRESS);
            if (!mShowing) {
                mShowing = true;
                if (!mIsLocked) {
                    mOverlayHeader.setVisibility(View.VISIBLE);
                    mOverlayOption.setVisibility(View.VISIBLE);
                    mPlayPause.setVisibility(View.VISIBLE);
                    mMenu.setVisibility(View.VISIBLE);
                    dimStatusBar(false);
                }
                mOverlayProgress.setVisibility(View.VISIBLE);
                if (mPresentation != null) mOverlayBackground.setVisibility(View.VISIBLE);
            }
            Message msg = mHandler.obtainMessage(FADE_OUT);
            if (timeout != 0) {
                mHandler.removeMessages(FADE_OUT);
                mHandler.sendMessageDelayed(msg, timeout);
            }
            updateOverlayPausePlay();
        }
    
    
        /**
         * hider overlay
         */
        private void hideOverlay(boolean fromUser) {
            if (mShowing) {
                mHandler.removeMessages(SHOW_PROGRESS);
                Log.i(TAG, "remove View!");
                if (mOverlayTips != null) mOverlayTips.setVisibility(View.INVISIBLE);
                if (!fromUser && !mIsLocked) {
                    mOverlayHeader.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
                    mOverlayOption.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
                    mOverlayProgress.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
                    mPlayPause.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
                    mMenu.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
                }
                if (mPresentation != null) {
                    mOverlayBackground.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
                    mOverlayBackground.setVisibility(View.INVISIBLE);
                }
                mOverlayHeader.setVisibility(View.INVISIBLE);
                mOverlayOption.setVisibility(View.INVISIBLE);
                mOverlayProgress.setVisibility(View.INVISIBLE);
                mPlayPause.setVisibility(View.INVISIBLE);
                mMenu.setVisibility(View.INVISIBLE);
                mShowing = false;
                dimStatusBar(true);
            }
        }
    
        /**
         * Dim the status bar and/or navigation icons when needed on Android 3.x.
         * Hide it on Android 4.0 and later
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        private void dimStatusBar(boolean dim) {
            if (!LibVlcUtil.isHoneycombOrLater() || !AndroidDevices.hasNavBar() || mIsNavMenu)
                return;
            int layout = 0;
            if (!AndroidDevices.hasCombBar() && LibVlcUtil.isJellyBeanOrLater())
                layout = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            int visibility =  (dim ? (AndroidDevices.hasCombBar()
                    ? View.SYSTEM_UI_FLAG_LOW_PROFILE
                            : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
                            : View.SYSTEM_UI_FLAG_VISIBLE) | layout;
            mSurface.setSystemUiVisibility(visibility);
            mSubtitlesSurface.setSystemUiVisibility(visibility);
        }
    
        private void updateOverlayPausePlay() {
            if (mLibVLC == null)
                return;
    
            if (mPresentation == null)
                mPlayPause.setBackgroundResource(mLibVLC.isPlaying() ? R.drawable.ic_pause_circle
                                : R.drawable.ic_play_circle);
            else
                mPlayPause.setBackgroundResource(mLibVLC.isPlaying() ? R.drawable.ic_pause_circle_big_o
                                : R.drawable.ic_play_circle_big_o);
        }
    
        /**
         * update the overlay
         */
        private int setOverlayProgress() {
            if (mLibVLC == null) {
                return 0;
            }
            int time = (int) mLibVLC.getTime();
            int length = (int) mLibVLC.getLength();
            if (length == 0) {
                Media media = MediaDatabase.getInstance().getMedia(mLocation);
                if (media != null)
                    length = (int) media.getLength();
            }
    
            // Update all view elements
            boolean isSeekable = mEnableJumpButtons && length > 0;
            mBackward.setVisibility(isSeekable ? View.VISIBLE : View.GONE);
            mForward.setVisibility(isSeekable ? View.VISIBLE : View.GONE);
            mSeekbar.setMax(length);
            mSeekbar.setProgress(time);
            mSysTime.setText(DateFormat.getTimeFormat(this).format(new Date(System.currentTimeMillis())));
            if (time >= 0) mTime.setText(Strings.millisToString(time));
            if (length >= 0) mLength.setText(mDisplayRemainingTime && length > 0
                    ? "- " + Strings.millisToString(length - time)
                    : Strings.millisToString(length));
    
            return time;
        }
    
        private void setESTracks() {
            if (mLastAudioTrack >= 0) {
                mLibVLC.setAudioTrack(mLastAudioTrack);
                mLastAudioTrack = -1;
            }
            if (mLastSpuTrack >= -1) {
                mLibVLC.setSpuTrack(mLastSpuTrack);
                mLastSpuTrack = -2;
            }
        }
    
        private void setESTrackLists(boolean force) {
            if(mAudioTracksList == null || force) {
                if (mLibVLC.getAudioTracksCount() > 2) {
                    mAudioTracksList = mLibVLC.getAudioTrackDescription();
                    mAudioTrack.setOnClickListener(mAudioTrackListener);
                    mAudioTrack.setVisibility(View.VISIBLE);
                }
                else {
                    mAudioTrack.setVisibility(View.GONE);
                    mAudioTrack.setOnClickListener(null);
                }
            }
            if (mSubtitleTracksList == null || force) {
                if (mLibVLC.getSpuTracksCount() > 0) {
                    mSubtitleTracksList = mLibVLC.getSpuTrackDescription();
                    mSubtitle.setOnClickListener(mSubtitlesListener);
                    mSubtitle.setVisibility(View.VISIBLE);
                }
                else {
                    mSubtitle.setVisibility(View.GONE);
                    mSubtitle.setOnClickListener(null);
                }
            }
        }
    
    
        /**
         *
         */
        private void play() {
            mLibVLC.play();
            mSurface.setKeepScreenOn(true);
        }
    
        /**
         *
         */
        private void pause() {
            mLibVLC.pause();
            mSurface.setKeepScreenOn(false);
        }
    
        /**
         * External extras:
         * - position (long) - position of the video to start with (in ms)
         */
        @SuppressWarnings({ "unchecked" })
        private void loadMedia() {
            mLocation = null;
            String title = getResources().getString(R.string.title);
            boolean dontParse = false;
            boolean fromStart = false;
            String itemTitle = null;
            int itemPosition = -1; // Index in the media list as passed by AudioServer (used only for vout transition internally)
            long intentPosition = -1; // position passed in by intent (ms)
    
            if (getIntent().getAction() != null
                    && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
                /* Started from external application 'content' */
                if (getIntent().getData() != null
                        && getIntent().getData().getScheme() != null
                        && getIntent().getData().getScheme().equals("content")) {
    
                    // Media or MMS URI
                    if(getIntent().getData().getHost().equals("media")
                            || getIntent().getData().getHost().equals("mms")) {
                        try {
                            Cursor cursor = getContentResolver().query(getIntent().getData(),
                                    new String[]{ MediaStore.Video.Media.DATA }, null, null, null);
                            if (cursor != null) {
                                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
                                if (cursor.moveToFirst())
                                    mLocation = LibVLC.PathToURI(cursor.getString(column_index));
                                cursor.close();
                            }
                        } catch (Exception e) {
                            Log.e(TAG, "Couldn't read the file from media or MMS");
                            encounteredError();
                        }
                    }
    
                    // Mail-based apps - download the stream to a temporary file and play it
                    else if(getIntent().getData().getHost().equals("com.fsck.k9.attachmentprovider")
                           || getIntent().getData().getHost().equals("gmail-ls")) {
                        try {
                            Cursor cursor = getContentResolver().query(getIntent().getData(),
                                    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();
                                Log.i(TAG, "Getting file " + filename + " from content:// URI");
    
                                InputStream is = getContentResolver().openInputStream(getIntent().getData());
                                OutputStream 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);
                                }
                                os.close();
                                is.close();
                                mLocation = LibVLC.PathToURI(Environment.getExternalStorageDirectory().getPath() + "/Download/" + filename);
                            }
                        } catch (Exception e) {
                            Log.e(TAG, "Couldn't download file from mail URI");
                            encounteredError();
                        }
                    }
    
                    // other content-based URI (probably file pickers)
                    else {
                        mLocation = getIntent().getData().getPath();
                    }
                } /* External application */
                else if (getIntent().getDataString() != null) {
                    // Plain URI
                    mLocation = getIntent().getDataString();
                    // Remove VLC prefix if needed
                    if (mLocation.startsWith("vlc://")) {
                        mLocation = mLocation.substring(6);
                    }
                    // Decode URI
                    if (!mLocation.contains("/")){
                        try {
                            mLocation = URLDecoder.decode(mLocation,"UTF-8");
                        } catch (UnsupportedEncodingException e) {
                            Log.w(TAG, "UnsupportedEncodingException while decoding MRL " + mLocation);
                        }
                    }
                } else {
                    Log.e(TAG, "Couldn't understand the intent");
                    encounteredError();
                }
    
                // Try to get the position
                if(getIntent().getExtras() != null)
                    intentPosition = getIntent().getExtras().getLong("position", -1);
            } /* ACTION_VIEW */
            /* Started from VideoListActivity */
            else if(getIntent().getAction() != null
                    && getIntent().getAction().equals(PLAY_FROM_VIDEOGRID)
                    && getIntent().getExtras() != null) {
                mLocation = getIntent().getExtras().getString("itemLocation");
                itemTitle = getIntent().getExtras().getString("itemTitle");
                dontParse = getIntent().getExtras().getBoolean("dontParse");
                fromStart = getIntent().getExtras().getBoolean("fromStart");
                itemPosition = getIntent().getExtras().getInt("itemPosition", -1);
            }
    
            mSurface.setKeepScreenOn(true);
    
            if(mLibVLC == null)
                return;
    
            /* WARNING: hack to avoid a crash in mediacodec on KitKat.
             * Disable hardware acceleration if the media has a ts extension. */
            if (mLocation != null && LibVlcUtil.isKitKatOrLater()) {
                String locationLC = mLocation.toLowerCase(Locale.ENGLISH);
                if (locationLC.endsWith(".ts")
                    || locationLC.endsWith(".tts")
                    || locationLC.endsWith(".m2t")
                    || locationLC.endsWith(".mts")
                    || locationLC.endsWith(".m2ts")) {
                    mDisabledHardwareAcceleration = true;
                    mPreviousHardwareAccelerationMode = mLibVLC.getHardwareAcceleration();
    //                mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);
                    mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);
                }
            }
            mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);
            /* Start / resume playback */
            if(dontParse && itemPosition >= 0) {
                // Provided externally from AudioService
                Log.d(TAG, "Continuing playback from AudioService at index " + itemPosition);
                savedIndexPosition = itemPosition;
                if(!mLibVLC.isPlaying()) {
                    // AudioService-transitioned playback for item after sleep and resume
                    mLibVLC.playIndex(savedIndexPosition);
                    dontParse = false;
                }
                else {
                    stopLoadingAnimation();
                    showOverlay();
                }
                updateNavStatus();
            } else if (savedIndexPosition > -1) {
                AudioServiceController.getInstance().stop(); // Stop the previous playback.
                mLibVLC.setMediaList();
                mLibVLC.playIndex(savedIndexPosition);
            } else if (mLocation != null && mLocation.length() > 0 && !dontParse) {
                AudioServiceController.getInstance().stop(); // Stop the previous playback.
                mLibVLC.setMediaList();
                mLibVLC.getMediaList().add(new Media(mLibVLC, mLocation));
                savedIndexPosition = mLibVLC.getMediaList().size() - 1;
                mLibVLC.playIndex(savedIndexPosition);
            }
            mCanSeek = false;
    
            if (mLocation != null && mLocation.length() > 0 && !dontParse) {
                // restore last position
                Media media = MediaDatabase.getInstance().getMedia(mLocation);
                if(media != null) {
                    // in media library
                    if(media.getTime() > 0 && !fromStart)
                        mLibVLC.setTime(media.getTime());
                    // Consume fromStart option after first use to prevent
                    // restarting again when playback is paused.
                    getIntent().putExtra("fromStart", false);
    
                    mLastAudioTrack = media.getAudioTrack();
                    mLastSpuTrack = media.getSpuTrack();
                } else {
                    // not in media library
                    long rTime = mSettings.getLong(PreferencesActivity.VIDEO_RESUME_TIME, -1);
                    Editor editor = mSettings.edit();
                    editor.putLong(PreferencesActivity.VIDEO_RESUME_TIME, -1);
                    editor.commit();
                    if(rTime > 0)
                        mLibVLC.setTime(rTime);
    
                    if(intentPosition > 0)
                        mLibVLC.setTime(intentPosition);
                }
    
                // Get possible subtitles
                String subtitleList_serialized = mSettings.getString(PreferencesActivity.VIDEO_SUBTITLE_FILES, null);
                ArrayList prefsList = new ArrayList();
                if(subtitleList_serialized != null) {
                    ByteArrayInputStream bis = new ByteArrayInputStream(subtitleList_serialized.getBytes());
                    try {
                        ObjectInputStream ois = new ObjectInputStream(bis);
                        prefsList = (ArrayList)ois.readObject();
                    } catch(ClassNotFoundException e) {}
                      catch (StreamCorruptedException e) {}
                      catch (IOException e) {}
                }
                for(String x : prefsList){
                    if(!mSubtitleSelectedFiles.contains(x))
                        mSubtitleSelectedFiles.add(x);
                 }
    
                // Get the title
                try {
                    title = URLDecoder.decode(mLocation, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                } catch (IllegalArgumentException e) {
                }
                if (title.startsWith("file:")) {
                    title = new File(title).getName();
                    int dotIndex = title.lastIndexOf('.');
                    if (dotIndex != -1)
                        title = title.substring(0, dotIndex);
                }
            } else if(itemTitle != null) {
                title = itemTitle;
            }
            mTitle.setText(title);
        }
    
        @SuppressWarnings("deprecation")
        private int getScreenRotation(){
            WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO /* Android 2.2 has getRotation */) {
                try {
                    Method m = display.getClass().getDeclaredMethod("getRotation");
                    return (Integer) m.invoke(display);
                } catch (Exception e) {
                    return Surface.ROTATION_0;
                }
            } else {
                return display.getOrientation();
            }
        }
    
        @TargetApi(Build.VERSION_CODES.GINGERBREAD)
        private int getScreenOrientation(){
            WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            int rot = getScreenRotation();
            /*
             * Since getRotation() returns the screen's "natural" orientation,
             * which is not guaranteed to be SCREEN_ORIENTATION_PORTRAIT,
             * we have to invert the SCREEN_ORIENTATION value if it is "naturally"
             * landscape.
             */
            @SuppressWarnings("deprecation")
            boolean defaultWide = display.getWidth() > display.getHeight();
            if(rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270)
                defaultWide = !defaultWide;
            if(defaultWide) {
                switch (rot) {
                case Surface.ROTATION_0:
                    return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                case Surface.ROTATION_90:
                    return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                case Surface.ROTATION_180:
                    // SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
                            : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                case Surface.ROTATION_270:
                    // SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
                            : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                default:
                    return 0;
                }
            } else {
                switch (rot) {
                case Surface.ROTATION_0:
                    return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                case Surface.ROTATION_90:
                    return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                case Surface.ROTATION_180:
                    // SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
                            : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                case Surface.ROTATION_270:
                    // SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
                            : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                default:
                    return 0;
                }
            }
        }
    
        public void showAdvancedOptions(View v) {
            CommonDialogs.advancedOptions(this, v, MenuType.Video);
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private void createPresentation() {
            if (mMediaRouter == null || mEnableCloneMode)
                return;
    
            // Get the current route and its presentation display.
            MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
                MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
    
            Display presentationDisplay = route != null ? route.getPresentationDisplay() : null;
    
            if (presentationDisplay != null) {
                // Show a new presentation if possible.
                Log.i(TAG, "Showing presentation on display: " + presentationDisplay);
                mPresentation = new SecondaryDisplay(this, presentationDisplay);
                mPresentation.setOnDismissListener(mOnDismissListener);
                try {
                    mPresentation.show();
                } catch (WindowManager.InvalidDisplayException ex) {
                    Log.w(TAG, "Couldn't show presentation!  Display was removed in "
                            + "the meantime.", ex);
                    mPresentation = null;
                }
            } else
                Log.i(TAG, "No secondary display detected");
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private void removePresentation() {
            if (mMediaRouter == null)
                return;
    
            // Dismiss the current presentation if the display has changed.
            Log.i(TAG, "Dismissing presentation because the current route no longer "
                    + "has a presentation display.");
            mLibVLC.pause(); // Stop sending frames to avoid a crash.
            finish(); //TODO restore the video on the new display instead of closing
            if (mPresentation != null) mPresentation.dismiss();
            mPresentation = null;
        }
    
        /**
         * Listens for when presentations are dismissed.
         */
        private final DialogInterface.OnDismissListener mOnDismissListener = new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                if (dialog == mPresentation) {
                    Log.i(TAG, "Presentation was dismissed.");
                    mPresentation = null;
                }
            }
        };
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private final class SecondaryDisplay extends Presentation {
            public final static String TAG = "VLC/SecondaryDisplay";
    
            private SurfaceView mSurface;
            private SurfaceView mSubtitlesSurface;
            private SurfaceHolder mSurfaceHolder;
            private SurfaceHolder mSubtitlesSurfaceHolder;
            private FrameLayout mSurfaceFrame;
            private LibVLC mLibVLC;
    
            public SecondaryDisplay(Context context, Display display) {
                super(context, display);
                if (context instanceof Activity) {
                    setOwnerActivity((Activity) context);
                }
                try {
                    mLibVLC = VLCInstance.getLibVlcInstance();
                } catch (LibVlcException e) {
                    Log.d(TAG, "LibVLC initialisation failed");
                    return;
                }
            }
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.player_remote);
    
                mSurface = (SurfaceView) findViewById(R.id.remote_player_surface);
                mSurfaceHolder = mSurface.getHolder();
                mSurfaceFrame = (FrameLayout) findViewById(R.id.remote_player_surface_frame);
                String chroma = mSettings.getString("chroma_format", "");
                if(LibVlcUtil.isGingerbreadOrLater() && chroma.equals("YV12")) {
                    mSurfaceHolder.setFormat(ImageFormat.YV12);
                } else if (chroma.equals("RV16")) {
                    mSurfaceHolder.setFormat(PixelFormat.RGB_565);
                } else {
                    mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
                }
    
                VideoPlayerActivity activity = (VideoPlayerActivity)getOwnerActivity();
                if (activity == null) {
                    Log.e(TAG, "Failed to get the VideoPlayerActivity instance, secondary display won't work");
                    return;
                }
    
                mSurfaceHolder.addCallback(activity.mSurfaceCallback);
    
                mSubtitlesSurface = (SurfaceView) findViewById(R.id.remote_subtitles_surface);
                mSubtitlesSurfaceHolder = mSubtitlesSurface.getHolder();
                mSubtitlesSurfaceHolder.setFormat(PixelFormat.RGBA_8888);
                mSubtitlesSurface.setZOrderMediaOverlay(true);
                mSubtitlesSurfaceHolder.addCallback(activity.mSubtitlesSurfaceCallback);
    
                /* Only show the subtitles surface when using "Full Acceleration" mode */
                if (mLibVLC != null && mLibVLC.getHardwareAcceleration() == LibVLC.HW_ACCELERATION_FULL)
                    mSubtitlesSurface.setVisibility(View.VISIBLE);
                Log.i(TAG, "Secondary display created");
            }
        }
    
        /**
         * Start the video loading animation.
         */
        private void startLoadingAnimation() {
            AnimationSet anim = new AnimationSet(true);
            RotateAnimation rotate = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            rotate.setDuration(800);
            rotate.setInterpolator(new DecelerateInterpolator());
            rotate.setRepeatCount(RotateAnimation.INFINITE);
            anim.addAnimation(rotate);
            mLoading.startAnimation(anim);
            mLoadingText.setVisibility(View.VISIBLE);
        }
    
        /**
         * Stop the video loading animation.
         */
        private void stopLoadingAnimation() {
            mLoading.setVisibility(View.INVISIBLE);
            mLoading.clearAnimation();
            mLoadingText.setVisibility(View.GONE);
        }
    
        public void onClickOverlayTips(View v) {
            mOverlayTips.setVisibility(View.GONE);
        }
    
        public void onClickDismissTips(View v) {
            mOverlayTips.setVisibility(View.GONE);
            Editor editor = mSettings.edit();
            editor.putBoolean(PREF_TIPS_SHOWN, true);
            editor.commit();
        }
    
        private void updateNavStatus() {
            mHasMenu = mLibVLC.getChapterCountForTitle(0) > 1 && mLibVLC.getTitleCount() > 1;
            mIsNavMenu = mHasMenu && mLibVLC.getTitle() == 0;
            /***
             * HACK ALERT: assume that any media with >1 titles = DVD with menus
             * Should be replaced with a more robust title/chapter selection popup
             */
    
            Log.d(TAG,
                    "updateNavStatus: getChapterCountForTitle(0) = "
                            + mLibVLC.getChapterCountForTitle(0)
                            + ", getTitleCount() = " + mLibVLC.getTitleCount());
            if (mIsNavMenu) {
                /*
                 * Keep the overlay hidden in order to have touch events directly
                 * transmitted to navigation handling.
                 */
                hideOverlay(false);
            }
            else if (mHasMenu) {
                setESTrackLists(true);
                setESTracks();
    
                /* Show the return to menu button. */
                mNavMenu.setVisibility(View.VISIBLE);
                mNavMenu.setOnClickListener(mNavMenuListener);
            }
            else
                mNavMenu.setVisibility(View.GONE);
    
        }
    }
    






沪ICP备19023445号-2号
友情链接