`

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

 
阅读更多

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

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

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

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

具体类文件目录是:


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

 

[java] view plaincopy
 
  1. /***************************************************************************** 
  2.  * VideoPlayerActivity.java 
  3.  ***************************************************************************** 
  4.  * Copyright © 2011-2014 VLC authors and VideoLAN 
  5.  * 
  6.  * This program is free software; you can redistribute it and/or modify 
  7.  * it under the terms of the GNU General Public License as published by 
  8.  * the Free Software Foundation; either version 2 of the License, or 
  9.  * (at your option) any later version. 
  10.  * 
  11.  * This program is distributed in the hope that it will be useful, 
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  14.  * GNU General Public License for more details. 
  15.  * 
  16.  * You should have received a copy of the GNU General Public License 
  17.  * along with this program; if not, write to the Free Software 
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 
  19.  *****************************************************************************/  
  20.   
  21. package org.videolan.vlc.gui.video;  
  22.   
  23. import java.io.ByteArrayInputStream;  
  24. import java.io.ByteArrayOutputStream;  
  25. import java.io.File;  
  26. import java.io.FileOutputStream;  
  27. import java.io.IOException;  
  28. import java.io.InputStream;  
  29. import java.io.ObjectInputStream;  
  30. import java.io.ObjectOutputStream;  
  31. import java.io.OutputStream;  
  32. import java.io.StreamCorruptedException;  
  33. import java.io.UnsupportedEncodingException;  
  34. import java.lang.reflect.Method;  
  35. import java.net.URLDecoder;  
  36. import java.util.ArrayList;  
  37. import java.util.Date;  
  38. import java.util.Locale;  
  39. import java.util.Map;  
  40.   
  41. import org.videolan.libvlc.EventHandler;  
  42. import org.videolan.libvlc.IVideoPlayer;  
  43. import org.videolan.libvlc.LibVLC;  
  44. import org.videolan.libvlc.LibVlcException;  
  45. import org.videolan.libvlc.LibVlcUtil;  
  46. import org.videolan.libvlc.Media;  
  47. import org.videolan.vlc.MediaDatabase;  
  48. import org.videolan.vlc.R;  
  49. import org.videolan.vlc.VLCApplication;  
  50. import org.videolan.vlc.audio.AudioServiceController;  
  51. import org.videolan.vlc.gui.CommonDialogs;  
  52. import org.videolan.vlc.gui.CommonDialogs.MenuType;  
  53. import org.videolan.vlc.gui.MainActivity;  
  54. import org.videolan.vlc.gui.PreferencesActivity;  
  55. import org.videolan.vlc.util.AndroidDevices;  
  56. import org.videolan.vlc.util.Strings;  
  57. import org.videolan.vlc.util.VLCInstance;  
  58. import org.videolan.vlc.util.WeakHandler;  
  59.   
  60. import android.annotation.TargetApi;  
  61. import android.app.Activity;  
  62. import android.app.AlertDialog;  
  63. import android.app.KeyguardManager;  
  64. import android.app.Presentation;  
  65. import android.content.BroadcastReceiver;  
  66. import android.content.Context;  
  67. import android.content.DialogInterface;  
  68. import android.content.Intent;  
  69. import android.content.IntentFilter;  
  70. import android.content.SharedPreferences;  
  71. import android.content.SharedPreferences.Editor;  
  72. import android.content.pm.ActivityInfo;  
  73. import android.content.res.Configuration;  
  74. import android.database.Cursor;  
  75. import android.graphics.Color;  
  76. import android.graphics.ImageFormat;  
  77. import android.graphics.PixelFormat;  
  78. import android.media.AudioManager;  
  79. import android.media.AudioManager.OnAudioFocusChangeListener;  
  80. import android.media.MediaRouter;  
  81. import android.os.Build;  
  82. import android.os.Bundle;  
  83. import android.os.Environment;  
  84. import android.os.Handler;  
  85. import android.os.Message;  
  86. import android.preference.PreferenceManager;  
  87. import android.provider.MediaStore;  
  88. import android.provider.Settings.SettingNotFoundException;  
  89. import android.text.format.DateFormat;  
  90. import android.util.DisplayMetrics;  
  91. import android.util.Log;  
  92. import android.view.Display;  
  93. import android.view.MotionEvent;  
  94. import android.view.Surface;  
  95. import android.view.SurfaceHolder;  
  96. import android.view.SurfaceHolder.Callback;  
  97. import android.view.SurfaceView;  
  98. import android.view.View;  
  99. import android.view.View.OnClickListener;  
  100. import android.view.View.OnSystemUiVisibilityChangeListener;  
  101. import android.view.ViewGroup.LayoutParams;  
  102. import android.view.WindowManager;  
  103. import android.view.animation.Animation;  
  104. import android.view.animation.AnimationSet;  
  105. import android.view.animation.AnimationUtils;  
  106. import android.view.animation.DecelerateInterpolator;  
  107. import android.view.animation.RotateAnimation;  
  108. import android.widget.FrameLayout;  
  109. import android.widget.ImageButton;  
  110. import android.widget.ImageView;  
  111. import android.widget.SeekBar;  
  112. import android.widget.SeekBar.OnSeekBarChangeListener;  
  113. import android.widget.TextView;  
  114.   
  115. public class VideoPlayerActivity extends Activity implements IVideoPlayer {  
  116.     public final static String TAG = "VLC/VideoPlayerActivity";  
  117.   
  118.     // Internal intent identifier to distinguish between internal launch and  
  119.     // external intent.  
  120.     private final static String PLAY_FROM_VIDEOGRID = "org.videolan.vlc.gui.video.PLAY_FROM_VIDEOGRID";  
  121.   
  122.     private SurfaceView mSurface;  
  123.     private SurfaceView mSubtitlesSurface;  
  124.     private SurfaceHolder mSurfaceHolder;  
  125.     private SurfaceHolder mSubtitlesSurfaceHolder;  
  126.     private FrameLayout mSurfaceFrame;  
  127.     private MediaRouter mMediaRouter;  
  128.     private MediaRouter.SimpleCallback mMediaRouterCallback;  
  129.     private SecondaryDisplay mPresentation;  
  130.     private LibVLC mLibVLC;  
  131.     private String mLocation;  
  132.   
  133.     private static final int SURFACE_BEST_FIT = 0;  
  134.     private static final int SURFACE_FIT_HORIZONTAL = 1;  
  135.     private static final int SURFACE_FIT_VERTICAL = 2;  
  136.     private static final int SURFACE_FILL = 3;  
  137.     private static final int SURFACE_16_9 = 4;  
  138.     private static final int SURFACE_4_3 = 5;  
  139.     private static final int SURFACE_ORIGINAL = 6;  
  140.     private int mCurrentSize = SURFACE_BEST_FIT;  
  141.   
  142.     private SharedPreferences mSettings;  
  143.   
  144.     /** Overlay */  
  145.     private View mOverlayHeader;  
  146.     private View mOverlayOption;  
  147.     private View mOverlayProgress;  
  148.     private View mOverlayBackground;  
  149.     private static final int OVERLAY_TIMEOUT = 4000;  
  150.     private static final int OVERLAY_INFINITE = 3600000;  
  151.     private static final int FADE_OUT = 1;  
  152.     private static final int SHOW_PROGRESS = 2;  
  153.     private static final int SURFACE_SIZE = 3;  
  154.     private static final int AUDIO_SERVICE_CONNECTION_SUCCESS = 5;  
  155.     private static final int AUDIO_SERVICE_CONNECTION_FAILED = 6;  
  156.     private static final int FADE_OUT_INFO = 4;  
  157.     private boolean mDragging;  
  158.     private boolean mShowing;  
  159.     private int mUiVisibility = -1;  
  160.     private SeekBar mSeekbar;  
  161.     private TextView mTitle;  
  162.     private TextView mSysTime;  
  163.     private TextView mBattery;  
  164.     private TextView mTime;  
  165.     private TextView mLength;  
  166.     private TextView mInfo;  
  167.     private ImageView mLoading;  
  168.     private TextView mLoadingText;  
  169.     private ImageButton mPlayPause;  
  170.     private ImageButton mBackward;  
  171.     private ImageButton mForward;  
  172.     private boolean mEnableJumpButtons;  
  173.     private boolean mEnableBrightnessGesture;  
  174.     private boolean mEnableCloneMode;  
  175.     private boolean mDisplayRemainingTime = false;  
  176.     private int mScreenOrientation;  
  177.     private ImageButton mAudioTrack;  
  178.     private ImageButton mSubtitle;  
  179.     private ImageButton mLock;  
  180.     private ImageButton mSize;  
  181.     private ImageButton mMenu;  
  182.     private boolean mIsLocked = false;  
  183.     private int mLastAudioTrack = -1;  
  184.     private int mLastSpuTrack = -2;  
  185.   
  186.     /** 
  187.      * For uninterrupted switching between audio and video mode 
  188.      */  
  189.     private boolean mSwitchingView;  
  190.     private boolean mEndReached;  
  191.     private boolean mCanSeek;  
  192.   
  193.     // Playlist  
  194.     private int savedIndexPosition = -1;  
  195.   
  196.     // size of the video  
  197.     private int mVideoHeight;  
  198.     private int mVideoWidth;  
  199.     private int mVideoVisibleHeight;  
  200.     private int mVideoVisibleWidth;  
  201.     private int mSarNum;  
  202.     private int mSarDen;  
  203.   
  204.     //Volume  
  205.     private AudioManager mAudioManager;  
  206.     private int mAudioMax;  
  207.     private OnAudioFocusChangeListener mAudioFocusListener;  
  208.   
  209.     //Touch Events  
  210.     private static final int TOUCH_NONE = 0;  
  211.     private static final int TOUCH_VOLUME = 1;  
  212.     private static final int TOUCH_BRIGHTNESS = 2;  
  213.     private static final int TOUCH_SEEK = 3;  
  214.     private int mTouchAction;  
  215.     private int mSurfaceYDisplayRange;  
  216.     private float mTouchY, mTouchX, mVol;  
  217.   
  218.     // Brightness  
  219.     private boolean mIsFirstBrightnessGesture = true;  
  220.   
  221.     // Tracks & Subtitles  
  222.     private Map<Integer,String> mAudioTracksList;  
  223.     private Map<Integer,String> mSubtitleTracksList;  
  224.     /** 
  225.      * Used to store a selected subtitle; see onActivityResult. 
  226.      * It is possible to have multiple custom subs in one session 
  227.      * (just like desktop VLC allows you as well.) 
  228.      */  
  229.     private final ArrayList<String> mSubtitleSelectedFiles = new ArrayList<String>();  
  230.   
  231.     // Whether fallback from HW acceleration to SW decoding was done.  
  232.     private boolean mDisabledHardwareAcceleration = false;  
  233.     private int mPreviousHardwareAccelerationMode;  
  234.   
  235.     // Tips  
  236.     private View mOverlayTips;  
  237.     private static final String PREF_TIPS_SHOWN = "video_player_tips_shown";  
  238.   
  239.     // Navigation handling (DVD, Blu-Ray...)  
  240.     private ImageButton mNavMenu;  
  241.     private boolean mHasMenu = false;  
  242.     private boolean mIsNavMenu = false;  
  243.   
  244.     @Override  
  245.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN)  
  246.     protected void onCreate(Bundle savedInstanceState) {  
  247.         super.onCreate(savedInstanceState);  
  248.         Log.i(TAG, "onCreate.");  
  249.         if (LibVlcUtil.isJellyBeanMR1OrLater()) {  
  250.             // Get the media router service (Miracast)  
  251.             mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);  
  252.             mMediaRouterCallback = new MediaRouter.SimpleCallback() {  
  253.                 @Override  
  254.                 public void onRoutePresentationDisplayChanged(  
  255.                         MediaRouter router, MediaRouter.RouteInfo info) {  
  256.                     Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);  
  257.                     removePresentation();  
  258.                 }  
  259.             };  
  260.             Log.d(TAG, "MediaRouter information : " + mMediaRouter  .toString());  
  261.         }  
  262.   
  263.         mSettings = PreferenceManager.getDefaultSharedPreferences(this);  
  264.   
  265.         /* Services and miscellaneous */  
  266.         mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);  
  267.         mAudioMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
  268.   
  269.         mEnableCloneMode = mSettings.getBoolean("enable_clone_mode"false);  
  270.         createPresentation();  
  271.         setContentView(mPresentation == null ? R.layout.player : R.layout.player_remote_control);  
  272.   
  273.         if (LibVlcUtil.isICSOrLater())  
  274.             getWindow().getDecorView().findViewById(android.R.id.content).setOnSystemUiVisibilityChangeListener(  
  275.                     new OnSystemUiVisibilityChangeListener() {  
  276.                         @Override  
  277.                         public void onSystemUiVisibilityChange(int visibility) {  
  278.                             if (visibility == mUiVisibility)  
  279.                                 return;  
  280.                             setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);  
  281.                             if (visibility == View.SYSTEM_UI_FLAG_VISIBLE && !mShowing && !isFinishing()) {  
  282.                                 showOverlay();  
  283.                             }  
  284.                             mUiVisibility = visibility;  
  285.                         }  
  286.                     }  
  287.             );  
  288.   
  289.         /** initialize Views an their Events */  
  290.         mOverlayHeader = findViewById(R.id.player_overlay_header);  
  291.         mOverlayOption = findViewById(R.id.option_overlay);  
  292.         mOverlayProgress = findViewById(R.id.progress_overlay);  
  293.         mOverlayBackground = findViewById(R.id.player_overlay_background);  
  294.   
  295.         /* header */  
  296.         mTitle = (TextView) findViewById(R.id.player_overlay_title);  
  297.         mSysTime = (TextView) findViewById(R.id.player_overlay_systime);  
  298.         mBattery = (TextView) findViewById(R.id.player_overlay_battery);  
  299.   
  300.         // Position and remaining time  
  301.         mTime = (TextView) findViewById(R.id.player_overlay_time);  
  302.         mTime.setOnClickListener(mRemainingTimeListener);  
  303.         mLength = (TextView) findViewById(R.id.player_overlay_length);  
  304.         mLength.setOnClickListener(mRemainingTimeListener);  
  305.   
  306.         // the info textView is not on the overlay  
  307.         mInfo = (TextView) findViewById(R.id.player_overlay_info);  
  308.   
  309.         mEnableBrightnessGesture = mSettings.getBoolean("enable_brightness_gesture"true);  
  310.         mScreenOrientation = Integer.valueOf(  
  311.                 mSettings.getString("screen_orientation_value""4" /*SCREEN_ORIENTATION_SENSOR*/));  
  312.   
  313.         mEnableJumpButtons = mSettings.getBoolean("enable_jump_buttons"false);  
  314.         mPlayPause = (ImageButton) findViewById(R.id.player_overlay_play);  
  315.         mPlayPause.setOnClickListener(mPlayPauseListener);  
  316.         mBackward = (ImageButton) findViewById(R.id.player_overlay_backward);  
  317.         mBackward.setOnClickListener(mBackwardListener);  
  318.         mForward = (ImageButton) findViewById(R.id.player_overlay_forward);  
  319.         mForward.setOnClickListener(mForwardListener);  
  320.   
  321.         mAudioTrack = (ImageButton) findViewById(R.id.player_overlay_audio);  
  322.         mAudioTrack.setVisibility(View.GONE);  
  323.         mSubtitle = (ImageButton) findViewById(R.id.player_overlay_subtitle);  
  324.         mSubtitle.setVisibility(View.GONE);  
  325.         mNavMenu = (ImageButton) findViewById(R.id.player_overlay_navmenu);  
  326.         mNavMenu.setVisibility(View.GONE);  
  327.   
  328.         mLock = (ImageButton) findViewById(R.id.lock_overlay_button);  
  329.         mLock.setOnClickListener(mLockListener);  
  330.   
  331.         mSize = (ImageButton) findViewById(R.id.player_overlay_size);  
  332.         mSize.setOnClickListener(mSizeListener);  
  333.   
  334.         mMenu = (ImageButton) findViewById(R.id.player_overlay_adv_function);  
  335.   
  336.         try {  
  337.             mLibVLC = VLCInstance.getLibVlcInstance();  
  338.         } catch (LibVlcException e) {  
  339.             Log.d(TAG, "LibVLC initialisation failed");  
  340.             return;  
  341.         }  
  342.   
  343.         mSurface = (SurfaceView) findViewById(R.id.player_surface);  
  344.         mSurfaceHolder = mSurface.getHolder();  
  345.         mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);  
  346.         String chroma = mSettings.getString("chroma_format""");  
  347.         if(LibVlcUtil.isGingerbreadOrLater() && chroma.equals("YV12")) {  
  348.             mSurfaceHolder.setFormat(ImageFormat.YV12);  
  349.         } else if (chroma.equals("RV16")) {  
  350.             mSurfaceHolder.setFormat(PixelFormat.RGB_565);  
  351.         } else {  
  352.             mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);  
  353.         }  
  354.   
  355.         mSubtitlesSurface = (SurfaceView) findViewById(R.id.subtitles_surface);  
  356.         mSubtitlesSurfaceHolder = mSubtitlesSurface.getHolder();  
  357.         mSubtitlesSurfaceHolder.setFormat(PixelFormat.RGBA_8888);  
  358.         mSubtitlesSurface.setZOrderMediaOverlay(true);  
  359.         if (mPresentation == null) {  
  360.             mSurfaceHolder.addCallback(mSurfaceCallback);  
  361.             mSubtitlesSurfaceHolder.addCallback(mSubtitlesSurfaceCallback);  
  362.         }  
  363.   
  364.         mSeekbar = (SeekBar) findViewById(R.id.player_overlay_seekbar);  
  365.         mSeekbar.setOnSeekBarChangeListener(mSeekListener);  
  366.   
  367.         /* Loading view */  
  368.         mLoading = (ImageView) findViewById(R.id.player_overlay_loading);  
  369.         mLoadingText = (TextView) findViewById(R.id.player_overlay_loading_text);  
  370.         startLoadingAnimation();  
  371.   
  372.         mSwitchingView = false;  
  373.         mEndReached = false;  
  374.   
  375.         // Clear the resume time, since it is only used for resumes in external  
  376.         // videos.  
  377.         SharedPreferences.Editor editor = mSettings.edit();  
  378.         editor.putLong(PreferencesActivity.VIDEO_RESUME_TIME, -1);  
  379.         // Also clear the subs list, because it is supposed to be per session  
  380.         // only (like desktop VLC). We don't want the customs subtitle file  
  381.         // to persist forever with this video.  
  382.         editor.putString(PreferencesActivity.VIDEO_SUBTITLE_FILES, null);  
  383.         editor.commit();  
  384.   
  385.         IntentFilter filter = new IntentFilter();  
  386.         filter.addAction(Intent.ACTION_BATTERY_CHANGED);  
  387.         filter.addAction(VLCApplication.SLEEP_INTENT);  
  388.         registerReceiver(mReceiver, filter);  
  389.   
  390.         Log.d(TAG,  
  391.                 "Hardware acceleration mode: "  
  392.                         + Integer.toString(mLibVLC.getHardwareAcceleration()));  
  393.   
  394.         /* Only show the subtitles surface when using "Full Acceleration" mode */  
  395.         if (mLibVLC.getHardwareAcceleration() == LibVLC.HW_ACCELERATION_FULL)  
  396.             mSubtitlesSurface.setVisibility(View.VISIBLE);  
  397.         // Signal to LibVLC that the videoPlayerActivity was created, thus the  
  398.         // SurfaceView is now available for MediaCodec direct rendering.  
  399.         mLibVLC.eventVideoPlayerActivityCreated(true);  
  400.         //mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);  
  401.         EventHandler em = EventHandler.getInstance();  
  402.         em.addHandler(eventHandler);  
  403.   
  404.         this.setVolumeControlStream(AudioManager.STREAM_MUSIC);  
  405.   
  406.         // Extra initialization when no secondary display is detected  
  407.         if (mPresentation == null) {  
  408.             // Orientation  
  409.             // 100 is the value for screen_orientation_start_lock  
  410.             setRequestedOrientation(mScreenOrientation != 100  
  411.                     ? mScreenOrientation  
  412.                     : getScreenOrientation());  
  413.             // Tips  
  414.             mOverlayTips = findViewById(R.id.player_overlay_tips);  
  415.             if(mSettings.getBoolean(PREF_TIPS_SHOWN, false))  
  416.                 mOverlayTips.setVisibility(View.GONE);  
  417.             else {  
  418.                 mOverlayTips.bringToFront();  
  419.                 mOverlayTips.invalidate();  
  420.             }  
  421.         } else  
  422.             setRequestedOrientation(getScreenOrientation());  
  423.   
  424.         updateNavStatus();  
  425.     }  
  426.   
  427.     @Override  
  428.     protected void onPause() {  
  429.         super.onPause();  
  430.         Log.i(TAG, "onPause. mSwitchingView="+mSwitchingView);  
  431.         if (mMediaRouter != null) {  
  432.             // Stop listening for changes to media routes.  
  433.             mediaRouterAddCallback(false);  
  434.         }  
  435.   
  436.         if(mSwitchingView) {  
  437.             Log.d(TAG, "mLocation = \"" + mLocation + "\"");  
  438.             AudioServiceController.getInstance().showWithoutParse(savedIndexPosition);  
  439.             AudioServiceController.getInstance().unbindAudioService(this);  
  440.             return;  
  441.         }  
  442.   
  443.         long time = mLibVLC.getTime();  
  444.         long length = mLibVLC.getLength();  
  445.         //remove saved position if in the last 5 seconds  
  446.         if (length - time < 5000)  
  447.             time = 0;  
  448.         else  
  449.             time -= 5000// go back 5 seconds, to compensate loading time  
  450.   
  451.         /* 
  452.          * Pausing here generates errors because the vout is constantly 
  453.          * trying to refresh itself every 80ms while the surface is not 
  454.          * accessible anymore. 
  455.          * To workaround that, we keep the last known position in the playlist 
  456.          * in savedIndexPosition to be able to restore it during onResume(). 
  457.          */  
  458.         mLibVLC.stop();  
  459.   
  460.         mSurface.setKeepScreenOn(false);  
  461.   
  462.         SharedPreferences.Editor editor = mSettings.edit();  
  463.         // Save position  
  464.         if (time >= 0 && mCanSeek) {  
  465.             if(MediaDatabase.getInstance().mediaItemExists(mLocation)) {  
  466.                 MediaDatabase.getInstance().updateMedia(  
  467.                         mLocation,  
  468.                         MediaDatabase.mediaColumn.MEDIA_TIME,  
  469.                         time);  
  470.             } else {  
  471.                 // Video file not in media library, store time just for onResume()  
  472.                 editor.putLong(PreferencesActivity.VIDEO_RESUME_TIME, time);  
  473.             }  
  474.         }  
  475.         // Save selected subtitles  
  476.         String subtitleList_serialized = null;  
  477.         if(mSubtitleSelectedFiles.size() > 0) {  
  478.             Log.d(TAG, "Saving selected subtitle files");  
  479.             ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  480.             try {  
  481.                 ObjectOutputStream oos = new ObjectOutputStream(bos);  
  482.                 oos.writeObject(mSubtitleSelectedFiles);  
  483.                 subtitleList_serialized = bos.toString();  
  484.             } catch(IOException e) {}  
  485.         }  
  486.         editor.putString(PreferencesActivity.VIDEO_SUBTITLE_FILES, subtitleList_serialized);  
  487.   
  488.         editor.commit();  
  489.         AudioServiceController.getInstance().unbindAudioService(this);  
  490.     }  
  491.   
  492.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  493.     @Override  
  494.     protected void onStop() {  
  495.         super.onStop();  
  496.         Log.i(TAG, "onStop.");  
  497.         // Dismiss the presentation when the activity is not visible.  
  498.         if (mPresentation != null) {  
  499.             Log.i(TAG, "Dismissing presentation because the activity is no longer visible.");  
  500.             mPresentation.dismiss();  
  501.             mPresentation = null;  
  502.         }  
  503.     }  
  504.   
  505.     @Override  
  506.     protected void onDestroy() {  
  507.         super.onDestroy();  
  508.         Log.i(TAG, "onDestroy.");  
  509.         unregisterReceiver(mReceiver);  
  510.   
  511.         EventHandler em = EventHandler.getInstance();  
  512.         em.removeHandler(eventHandler);  
  513.   
  514.         // MediaCodec opaque direct rendering should not be used anymore since there is no surface to attach.  
  515.         mLibVLC.eventVideoPlayerActivityCreated(false);  
  516.         // HW acceleration was temporarily disabled because of an error, restore the previous value.  
  517.         if (mDisabledHardwareAcceleration)  
  518.             mLibVLC.setHardwareAcceleration(mPreviousHardwareAccelerationMode);  
  519.   
  520.         mAudioManager = null;  
  521.     }  
  522.   
  523.     @Override  
  524.     protected void onResume() {  
  525.         super.onResume();  
  526.         Log.i(TAG, "onResume.");  
  527.           
  528.         mSwitchingView = false;  
  529.         AudioServiceController.getInstance().bindAudioService(this,  
  530.                 new AudioServiceController.AudioServiceConnectionListener() {  
  531.             @Override  
  532.             public void onConnectionSuccess() {  
  533.                 mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_SUCCESS);  
  534.             }  
  535.   
  536.             @Override  
  537.             public void onConnectionFailed() {  
  538.                 mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_FAILED);  
  539.             }  
  540.         });  
  541.   
  542.         if (mMediaRouter != null) {  
  543.             // Listen for changes to media routes.  
  544.             mediaRouterAddCallback(true);  
  545.         }  
  546.     }  
  547.   
  548.     /** 
  549.      * Add or remove MediaRouter callbacks. This is provided for version targeting. 
  550.      * 
  551.      * @param add true to add, false to remove 
  552.      */  
  553.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  554.     private void mediaRouterAddCallback(boolean add) {  
  555.         if(!LibVlcUtil.isJellyBeanMR1OrLater() || mMediaRouter == nullreturn;  
  556.   
  557.         if(add)  
  558.             mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mMediaRouterCallback);  
  559.         else  
  560.             mMediaRouter.removeCallback(mMediaRouterCallback);  
  561.     }  
  562.   
  563.     private void startPlayback() {  
  564.          Log.i(TAG, "startPlayback.");  
  565.            
  566.           
  567.         loadMedia();  
  568.   
  569.         /* 
  570.          * if the activity has been paused by pressing the power button, 
  571.          * pressing it again will show the lock screen. 
  572.          * But onResume will also be called, even if vlc-android is still in the background. 
  573.          * To workaround that, pause playback if the lockscreen is displayed 
  574.          */  
  575.         mHandler.postDelayed(new Runnable() {  
  576.             @Override  
  577.             public void run() {  
  578.                 if (mLibVLC != null && mLibVLC.isPlaying()) {  
  579.                     KeyguardManager km = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);  
  580.                     if (km.inKeyguardRestrictedInputMode())  
  581.                         mLibVLC.pause();  
  582.                 }  
  583.             }}, 500);  
  584.   
  585.         // Add any selected subtitle file from the file picker  
  586.         if(mSubtitleSelectedFiles.size() > 0) {  
  587.             for(String file : mSubtitleSelectedFiles) {  
  588.                 Log.i(TAG, "Adding user-selected subtitle " + file);  
  589.                 mLibVLC.addSubtitleTrack(file);  
  590.             }  
  591.         }  
  592.     }  
  593.   
  594.     @Override  
  595.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  596.         if(data == nullreturn;  
  597.   
  598.         if(data.getDataString() == null) {  
  599.             Log.d(TAG, "Subtitle selection dialog was cancelled");  
  600.         }  
  601.         if(data.getData() == nullreturn;  
  602.   
  603.         String subtitlePath = data.getData().getPath();  
  604.         if(requestCode == CommonDialogs.INTENT_SPECIFIC) {  
  605.             Log.d(TAG, "Specific subtitle file: " + subtitlePath);  
  606.         } else if(requestCode == CommonDialogs.INTENT_GENERIC) {  
  607.             Log.d(TAG, "Generic subtitle file: " + subtitlePath);  
  608.         }  
  609.         mSubtitleSelectedFiles.add(subtitlePath);  
  610.     }  
  611.   
  612.     public static void start(Context context, String location) {  
  613.         start(context, location, null, -1falsefalse);  
  614.     }  
  615.   
  616.     public static void start(Context context, String location, Boolean fromStart) {  
  617.         start(context, location, null, -1false, fromStart);  
  618.     }  
  619.   
  620.     public static void start(Context context, String location, String title, Boolean dontParse) {  
  621.         start(context, location, title, -1, dontParse, false);  
  622.     }  
  623.   
  624.     public static void start(Context context, String location, String title, int position, Boolean dontParse) {  
  625.         start(context, location, title, position, dontParse, false);  
  626.     }  
  627.   
  628.     public static void start(Context context, String location, String title, int position, Boolean dontParse, Boolean fromStart) {  
  629.         Intent intent = new Intent(context, VideoPlayerActivity.class);  
  630.         intent.setAction(VideoPlayerActivity.PLAY_FROM_VIDEOGRID);  
  631.         intent.putExtra("itemLocation", location);  
  632.         intent.putExtra("itemTitle", title);  
  633.         intent.putExtra("dontParse", dontParse);  
  634.         intent.putExtra("fromStart", fromStart);  
  635.         intent.putExtra("itemPosition", position);  
  636.   
  637.         if (dontParse)  
  638.             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);  
  639.   
  640.         context.startActivity(intent);  
  641.     }  
  642.   
  643.     private final BroadcastReceiver mReceiver = new BroadcastReceiver()  
  644.     {  
  645.         @Override  
  646.         public void onReceive(Context context, Intent intent)  
  647.         {  
  648.             String action = intent.getAction();  
  649.             if (action.equalsIgnoreCase(Intent.ACTION_BATTERY_CHANGED)) {  
  650.                 int batteryLevel = intent.getIntExtra("level"0);  
  651.                 if (batteryLevel >= 50)  
  652.                     mBattery.setTextColor(Color.GREEN);  
  653.                 else if (batteryLevel >= 30)  
  654.                     mBattery.setTextColor(Color.YELLOW);  
  655.                 else  
  656.                     mBattery.setTextColor(Color.RED);  
  657.                 mBattery.setText(String.format("%d%%", batteryLevel));  
  658.             }  
  659.             else if (action.equalsIgnoreCase(VLCApplication.SLEEP_INTENT)) {  
  660.                 finish();  
  661.             }  
  662.         }  
  663.     };  
  664.   
  665.     @Override  
  666.     public boolean onTrackballEvent(MotionEvent event) {  
  667.         showOverlay();  
  668.         return true;  
  669.     }  
  670.   
  671.     @Override  
  672.     public void onConfigurationChanged(Configuration newConfig) {  
  673.         setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);  
  674.         super.onConfigurationChanged(newConfig);  
  675.     }  
  676.   
  677.     @Override  
  678.     public void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {  
  679.         if (width * height == 0)  
  680.             return;  
  681.   
  682.         // store video size  
  683.         mVideoHeight = height;  
  684.         mVideoWidth = width;  
  685.         mVideoVisibleHeight = visible_height;  
  686.         mVideoVisibleWidth  = visible_width;  
  687.         mSarNum = sar_num;  
  688.         mSarDen = sar_den;  
  689.         Message msg = mHandler.obtainMessage(SURFACE_SIZE);  
  690.         mHandler.sendMessage(msg);  
  691.     }  
  692.   
  693.     /** 
  694.      * Lock screen rotation 
  695.      */  
  696.     private void lockScreen() {  
  697.         if(mScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  698.             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)  
  699.                 setRequestedOrientation(14 /* SCREEN_ORIENTATION_LOCKED */);  
  700.             else  
  701.                 setRequestedOrientation(getScreenOrientation());  
  702.         }  
  703.         showInfo(R.string.locked, 1000);  
  704.         mLock.setBackgroundResource(R.drawable.ic_locked);  
  705.         mTime.setEnabled(false);  
  706.         mSeekbar.setEnabled(false);  
  707.         mLength.setEnabled(false);  
  708.         hideOverlay(true);  
  709.     }  
  710.   
  711.     /** 
  712.      * Remove screen lock 
  713.      */  
  714.     private void unlockScreen() {  
  715.         if(mScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR)  
  716.             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);  
  717.         showInfo(R.string.unlocked, 1000);  
  718.         mLock.setBackgroundResource(R.drawable.ic_lock);  
  719.         mTime.setEnabled(true);  
  720.         mSeekbar.setEnabled(true);  
  721.         mLength.setEnabled(true);  
  722.         mShowing = false;  
  723.         showOverlay();  
  724.     }  
  725.   
  726.     /** 
  727.      * Show text in the info view for "duration" milliseconds 
  728.      * @param text 
  729.      * @param duration 
  730.      */  
  731.     private void showInfo(String text, int duration) {  
  732.         mInfo.setVisibility(View.VISIBLE);  
  733.         mInfo.setText(text);  
  734.         mHandler.removeMessages(FADE_OUT_INFO);  
  735.         mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, duration);  
  736.     }  
  737.   
  738.     private void showInfo(int textid, int duration) {  
  739.         mInfo.setVisibility(View.VISIBLE);  
  740.         mInfo.setText(textid);  
  741.         mHandler.removeMessages(FADE_OUT_INFO);  
  742.         mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, duration);  
  743.     }  
  744.   
  745.     /** 
  746.      * Show text in the info view 
  747.      * @param text 
  748.      */  
  749.     private void showInfo(String text) {  
  750.         mInfo.setVisibility(View.VISIBLE);  
  751.         mInfo.setText(text);  
  752.         mHandler.removeMessages(FADE_OUT_INFO);  
  753.     }  
  754.   
  755.     /** 
  756.      * hide the info view with "delay" milliseconds delay 
  757.      * @param delay 
  758.      */  
  759.     private void hideInfo(int delay) {  
  760.         mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, delay);  
  761.     }  
  762.   
  763.     /** 
  764.      * hide the info view 
  765.      */  
  766.     private void hideInfo() {  
  767.         hideInfo(0);  
  768.     }  
  769.   
  770.     private void fadeOutInfo() {  
  771.         if (mInfo.getVisibility() == View.VISIBLE)  
  772.             mInfo.startAnimation(AnimationUtils.loadAnimation(  
  773.                     VideoPlayerActivity.this, android.R.anim.fade_out));  
  774.         mInfo.setVisibility(View.INVISIBLE);  
  775.     }  
  776.   
  777.     @TargetApi(Build.VERSION_CODES.FROYO)  
  778.     private int changeAudioFocus(boolean acquire) {  
  779.         if(!LibVlcUtil.isFroyoOrLater()) // NOP if not supported  
  780.             return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;  
  781.   
  782.         if (mAudioFocusListener == null) {  
  783.             mAudioFocusListener = new OnAudioFocusChangeListener() {  
  784.                 @Override  
  785.                 public void onAudioFocusChange(int focusChange) {  
  786.                     /* 
  787.                      * Pause playback during alerts and notifications 
  788.                      */  
  789.                     switch (focusChange)  
  790.                     {  
  791.                         case AudioManager.AUDIOFOCUS_LOSS:  
  792.                         case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:  
  793.                         case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:  
  794.                             if (mLibVLC.isPlaying())  
  795.                                 mLibVLC.pause();  
  796.                             break;  
  797.                         case AudioManager.AUDIOFOCUS_GAIN:  
  798.                         case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:  
  799.                         case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:  
  800.                             if (!mLibVLC.isPlaying())  
  801.                                 mLibVLC.play();  
  802.                             break;  
  803.                     }  
  804.                 }  
  805.             };  
  806.         }  
  807.   
  808.         int result;  
  809.         if(acquire) {  
  810.             result = mAudioManager.requestAudioFocus(mAudioFocusListener,  
  811.                     AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);  
  812.             mAudioManager.setParameters("bgm_state=true");  
  813.         }  
  814.         else {  
  815.             if (mAudioManager != null) {  
  816.                 result = mAudioManager.abandonAudioFocus(mAudioFocusListener);  
  817.                 mAudioManager.setParameters("bgm_state=false");  
  818.             }  
  819.             else  
  820.                 result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;  
  821.         }  
  822.   
  823.         return result;  
  824.     }  
  825.   
  826.     /** 
  827.      *  Handle libvlc asynchronous events 
  828.      */  
  829.     private final Handler eventHandler = new VideoPlayerEventHandler(this);  
  830.   
  831.     private static class VideoPlayerEventHandler extends WeakHandler<VideoPlayerActivity> {  
  832.         public VideoPlayerEventHandler(VideoPlayerActivity owner) {  
  833.             super(owner);  
  834.         }  
  835.   
  836.         @Override  
  837.         public void handleMessage(Message msg) {  
  838.             VideoPlayerActivity activity = getOwner();  
  839.             if(activity == nullreturn;  
  840.             // Do not handle events if we are leaving the VideoPlayerActivity  
  841.             if (activity.mSwitchingView) return;  
  842.   
  843.             switch (msg.getData().getInt("event")) {  
  844.                 case EventHandler.MediaParsedChanged:  
  845.                     Log.i(TAG, "MediaParsedChanged");  
  846.                     activity.updateNavStatus();  
  847.                     if (!activity.mHasMenu && activity.mLibVLC.getVideoTracksCount() < 1) {  
  848.                         Log.i(TAG, "No video track, open in audio mode");  
  849.                         activity.switchToAudioMode();  
  850.                     }  
  851.                     break;  
  852.                 case EventHandler.MediaPlayerPlaying:  
  853.                     Log.i(TAG, "MediaPlayerPlaying");  
  854.                     activity.stopLoadingAnimation();  
  855.                     activity.showOverlay();  
  856.                     /** FIXME: update the track list when it changes during the 
  857.                      *  playback. (#7540) */  
  858.                     activity.setESTrackLists(true);  
  859.                     activity.setESTracks();  
  860.                     activity.changeAudioFocus(true);  
  861.                     activity.updateNavStatus();  
  862.                     break;  
  863.                 case EventHandler.MediaPlayerPaused:  
  864.                     Log.i(TAG, "MediaPlayerPaused");  
  865.                     break;  
  866.                 case EventHandler.MediaPlayerStopped:  
  867.                     Log.i(TAG, "MediaPlayerStopped");  
  868.                     activity.changeAudioFocus(false);  
  869.                     break;  
  870.                 case EventHandler.MediaPlayerEndReached:  
  871.                     Log.i(TAG, "MediaPlayerEndReached");  
  872.                     activity.changeAudioFocus(false);  
  873.                     activity.endReached();  
  874.                     break;  
  875.                 case EventHandler.MediaPlayerVout:  
  876.                     activity.updateNavStatus();  
  877.                     if (!activity.mHasMenu)  
  878.                         activity.handleVout(msg);  
  879.                     break;  
  880.                 case EventHandler.MediaPlayerPositionChanged:  
  881.                     if (!activity.mCanSeek)  
  882.                         activity.mCanSeek = true;  
  883.                     //don't spam the logs  
  884.                     break;  
  885.                 case EventHandler.MediaPlayerEncounteredError:  
  886.                     Log.i(TAG, "MediaPlayerEncounteredError");  
  887.                     activity.encounteredError();  
  888.                     break;  
  889.                 case EventHandler.HardwareAccelerationError:  
  890.                     Log.i(TAG, "HardwareAccelerationError");  
  891.                     activity.handleHardwareAccelerationError();  
  892.                     break;  
  893.                 case EventHandler.MediaPlayerTimeChanged:  
  894.                     // avoid useless error logs  
  895.                     break;  
  896.                 default:  
  897.                     Log.e(TAG, String.format("Event not handled (0x%x)", msg.getData().getInt("event")));  
  898.                     break;  
  899.             }  
  900.             activity.updateOverlayPausePlay();  
  901.         }  
  902.     };  
  903.   
  904.     /** 
  905.      * Handle resize of the surface and the overlay 
  906.      */  
  907.     private final Handler mHandler = new VideoPlayerHandler(this);  
  908.   
  909.     private static class VideoPlayerHandler extends WeakHandler<VideoPlayerActivity> {  
  910.         public VideoPlayerHandler(VideoPlayerActivity owner) {  
  911.             super(owner);  
  912.         }  
  913.   
  914.         @Override  
  915.         public void handleMessage(Message msg) {  
  916.             VideoPlayerActivity activity = getOwner();  
  917.             if(activity == null// WeakReference could be GC'ed early  
  918.                 return;  
  919.   
  920.             switch (msg.what) {  
  921.                 case FADE_OUT:  
  922.                     activity.hideOverlay(false);  
  923.                     break;  
  924.                 case SHOW_PROGRESS:  
  925.                     int pos = activity.setOverlayProgress();  
  926.                     if (activity.canShowProgress()) {  
  927.                         msg = obtainMessage(SHOW_PROGRESS);  
  928.                         sendMessageDelayed(msg, 1000 - (pos % 1000));  
  929.                     }  
  930.                     break;  
  931.                 case SURFACE_SIZE:  
  932.                     activity.changeSurfaceSize();  
  933.                     break;  
  934.                 case FADE_OUT_INFO:  
  935.                     activity.fadeOutInfo();  
  936.                     break;  
  937.                 case AUDIO_SERVICE_CONNECTION_SUCCESS:  
  938.                     activity.startPlayback();  
  939.                     break;  
  940.                 case AUDIO_SERVICE_CONNECTION_FAILED:  
  941.                     activity.finish();  
  942.                     break;  
  943.             }  
  944.         }  
  945.     };  
  946.   
  947.     private boolean canShowProgress() {  
  948.         return !mDragging && mShowing && mLibVLC.isPlaying();  
  949.     }  
  950.   
  951.     private void endReached() {  
  952.         if(mLibVLC.getMediaList().expandMedia(savedIndexPosition) == 0) {  
  953.             Log.d(TAG, "Found a video playlist, expanding it");  
  954.             eventHandler.postDelayed(new Runnable() {  
  955.                 @Override  
  956.                 public void run() {  
  957.                     loadMedia();  
  958.                 }  
  959.             }, 1000);  
  960.         } else {  
  961.             /* Exit player when reaching the end */  
  962.             mEndReached = true;  
  963.             finish();  
  964.         }  
  965.     }  
  966.   
  967.     private void encounteredError() {  
  968.         /* Encountered Error, exit player with a message */  
  969.         AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)  
  970.         .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {  
  971.             @Override  
  972.             public void onClick(DialogInterface dialog, int id) {  
  973.                 finish();  
  974.             }  
  975.         })  
  976.         .setTitle(R.string.encountered_error_title)  
  977.         .setMessage(R.string.encountered_error_message)  
  978.         .create();  
  979.         dialog.show();  
  980.     }  
  981.   
  982.     public void eventHardwareAccelerationError() {  
  983.         EventHandler em = EventHandler.getInstance();  
  984.         em.callback(EventHandler.HardwareAccelerationError, new Bundle());  
  985.     }  
  986.   
  987.     private void handleHardwareAccelerationError() {  
  988.         mLibVLC.stop();  
  989.         AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)  
  990.         .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {  
  991.             @Override  
  992.             public void onClick(DialogInterface dialog, int id) {  
  993.                 mDisabledHardwareAcceleration = true;  
  994.                 mPreviousHardwareAccelerationMode = mLibVLC.getHardwareAcceleration();  
  995.                 mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);  
  996.                 mSubtitlesSurface.setVisibility(View.INVISIBLE);  
  997.                 loadMedia();  
  998.             }  
  999.         })  
  1000.         .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {  
  1001.             @Override  
  1002.             public void onClick(DialogInterface dialog, int id) {  
  1003.                 finish();  
  1004.             }  
  1005.         })  
  1006.         .setTitle(R.string.hardware_acceleration_error_title)  
  1007.         .setMessage(R.string.hardware_acceleration_error_message)  
  1008.         .create();  
  1009.         if(!isFinishing())  
  1010.             dialog.show();  
  1011.     }  
  1012.   
  1013.     private void handleVout(Message msg) {  
  1014.         if (msg.getData().getInt("data") == 0 && !mEndReached) {  
  1015.             /* Video track lost, open in audio mode */  
  1016.             Log.i(TAG, "Video track lost, switching to audio");  
  1017.             mSwitchingView = true;  
  1018.             finish();  
  1019.         }  
  1020.     }  
  1021.   
  1022.     private void switchToAudioMode() {  
  1023.       
  1024.           
  1025.         mSwitchingView = true;  
  1026.         // Show the MainActivity if it is not in background.  
  1027.         if (getIntent().getAction() != null  
  1028.             && getIntent().getAction().equals(Intent.ACTION_VIEW)) {  
  1029.             Intent i = new Intent(this, MainActivity.class);  
  1030.             startActivity(i);  
  1031.         }  
  1032.         finish();  
  1033.     }  
  1034.   
  1035.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  1036.     private void changeSurfaceSize() {  
  1037.         int sw;  
  1038.         int sh;  
  1039.   
  1040.         // get screen size  
  1041.         if (mPresentation == null) {  
  1042.             sw = getWindow().getDecorView().getWidth();  
  1043.             sh = getWindow().getDecorView().getHeight();  
  1044.         } else {  
  1045.             sw = mPresentation.getWindow().getDecorView().getWidth();  
  1046.             sh = mPresentation.getWindow().getDecorView().getHeight();  
  1047.         }  
  1048.   
  1049.         double dw = sw, dh = sh;  
  1050.         boolean isPortrait;  
  1051.   
  1052.         if (mPresentation == null) {  
  1053.             // getWindow().getDecorView() doesn't always take orientation into account, we have to correct the values  
  1054.             isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;  
  1055.         } else {  
  1056.             isPortrait = false;  
  1057.         }  
  1058.   
  1059.         if (sw > sh && isPortrait || sw < sh && !isPortrait) {  
  1060.             dw = sh;  
  1061.             dh = sw;  
  1062.         }  
  1063.   
  1064.         // sanity check  
  1065.         if (dw * dh == 0 || mVideoWidth * mVideoHeight == 0) {  
  1066.             Log.e(TAG, "Invalid surface size");  
  1067.             return;  
  1068.         }  
  1069.   
  1070.         // compute the aspect ratio  
  1071.         double ar, vw;  
  1072.         if (mSarDen == mSarNum) {  
  1073.             /* No indication about the density, assuming 1:1 */  
  1074.             vw = mVideoVisibleWidth;  
  1075.             ar = (double)mVideoVisibleWidth / (double)mVideoVisibleHeight;  
  1076.         } else {  
  1077.             /* Use the specified aspect ratio */  
  1078.             vw = mVideoVisibleWidth * (double)mSarNum / mSarDen;  
  1079.             ar = vw / mVideoVisibleHeight;  
  1080.         }  
  1081.   
  1082.         // compute the display aspect ratio  
  1083.         double dar = dw / dh;  
  1084.   
  1085.         switch (mCurrentSize) {  
  1086.             case SURFACE_BEST_FIT:  
  1087.                 if (dar < ar)  
  1088.                     dh = dw / ar;  
  1089.                 else  
  1090.                     dw = dh * ar;  
  1091.                 break;  
  1092.             case SURFACE_FIT_HORIZONTAL:  
  1093.                 dh = dw / ar;  
  1094.                 break;  
  1095.             case SURFACE_FIT_VERTICAL:  
  1096.                 dw = dh * ar;  
  1097.                 break;  
  1098.             case SURFACE_FILL:  
  1099.                 break;  
  1100.             case SURFACE_16_9:  
  1101.                 ar = 16.0 / 9.0;  
  1102.                 if (dar < ar)  
  1103.                     dh = dw / ar;  
  1104.                 else  
  1105.                     dw = dh * ar;  
  1106.                 break;  
  1107.             case SURFACE_4_3:  
  1108.                 ar = 4.0 / 3.0;  
  1109.                 if (dar < ar)  
  1110.                     dh = dw / ar;  
  1111.                 else  
  1112.                     dw = dh * ar;  
  1113.                 break;  
  1114.             case SURFACE_ORIGINAL:  
  1115.                 dh = mVideoVisibleHeight;  
  1116.                 dw = vw;  
  1117.                 break;  
  1118.         }  
  1119.   
  1120.         SurfaceView surface;  
  1121.         SurfaceView subtitlesSurface;  
  1122.         SurfaceHolder surfaceHolder;  
  1123.         SurfaceHolder subtitlesSurfaceHolder;  
  1124.         FrameLayout surfaceFrame;  
  1125.   
  1126.         if (mPresentation == null) {  
  1127.             surface = mSurface;  
  1128.             subtitlesSurface = mSubtitlesSurface;  
  1129.             surfaceHolder = mSurfaceHolder;  
  1130.             subtitlesSurfaceHolder = mSubtitlesSurfaceHolder;  
  1131.             surfaceFrame = mSurfaceFrame;  
  1132.         } else {  
  1133.             surface = mPresentation.mSurface;  
  1134.             subtitlesSurface = mPresentation.mSubtitlesSurface;  
  1135.             surfaceHolder = mPresentation.mSurfaceHolder;  
  1136.             subtitlesSurfaceHolder = mPresentation.mSubtitlesSurfaceHolder;  
  1137.             surfaceFrame = mPresentation.mSurfaceFrame;  
  1138.         }  
  1139.   
  1140.         // force surface buffer size  
  1141.         surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);  
  1142.         subtitlesSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);  
  1143.   
  1144.         // set display size  
  1145.         LayoutParams lp = surface.getLayoutParams();  
  1146.         lp.width  = (int) Math.ceil(dw * mVideoWidth / mVideoVisibleWidth);  
  1147.         lp.height = (int) Math.ceil(dh * mVideoHeight / mVideoVisibleHeight);  
  1148.         surface.setLayoutParams(lp);  
  1149.         subtitlesSurface.setLayoutParams(lp);  
  1150.   
  1151.         // set frame size (crop if necessary)  
  1152.         lp = surfaceFrame.getLayoutParams();  
  1153.         lp.width = (int) Math.floor(dw);  
  1154.         lp.height = (int) Math.floor(dh);  
  1155.         surfaceFrame.setLayoutParams(lp);  
  1156.   
  1157.         surface.invalidate();  
  1158.         subtitlesSurface.invalidate();  
  1159.     }  
  1160.   
  1161.     /** 
  1162.      * show/hide the overlay 
  1163.      */  
  1164.   
  1165.     @Override  
  1166.     public boolean onTouchEvent(MotionEvent event) {  
  1167.         if (mIsLocked) {  
  1168.             // locked, only handle show/hide & ignore all actions  
  1169.             if (event.getAction() == MotionEvent.ACTION_UP) {  
  1170.                 if (!mShowing) {  
  1171.                     showOverlay();  
  1172.                 } else {  
  1173.                     hideOverlay(true);  
  1174.                 }  
  1175.             }  
  1176.             return false;  
  1177.         }  
  1178.   
  1179.         DisplayMetrics screen = new DisplayMetrics();  
  1180.         getWindowManager().getDefaultDisplay().getMetrics(screen);  
  1181.   
  1182.         if (mSurfaceYDisplayRange == 0)  
  1183.             mSurfaceYDisplayRange = Math.min(screen.widthPixels, screen.heightPixels);  
  1184.   
  1185.         float y_changed = event.getRawY() - mTouchY;  
  1186.         float x_changed = event.getRawX() - mTouchX;  
  1187.   
  1188.         // coef is the gradient's move to determine a neutral zone  
  1189.         float coef = Math.abs (y_changed / x_changed);  
  1190.         float xgesturesize = ((x_changed / screen.xdpi) * 2.54f);  
  1191.   
  1192.         /* Offset for Mouse Events */  
  1193.         int[] offset = new int[2];  
  1194.         mSurface.getLocationOnScreen(offset);  
  1195.         int xTouch = Math.round((event.getRawX() - offset[0]) * mVideoWidth / mSurface.getWidth());  
  1196.         int yTouch = Math.round((event.getRawY() - offset[1]) * mVideoHeight / mSurface.getHeight());  
  1197.   
  1198.         switch (event.getAction()) {  
  1199.   
  1200.         case MotionEvent.ACTION_DOWN:  
  1201.             // Audio  
  1202.             mTouchY = event.getRawY();  
  1203.             mVol = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);  
  1204.             mTouchAction = TOUCH_NONE;  
  1205.             // Seek  
  1206.             mTouchX = event.getRawX();  
  1207.             // Mouse events for the core  
  1208.             LibVLC.sendMouseEvent(MotionEvent.ACTION_DOWN, 0, xTouch, yTouch);  
  1209.             break;  
  1210.   
  1211.         case MotionEvent.ACTION_MOVE:  
  1212.             // Mouse events for the core  
  1213.             LibVLC.sendMouseEvent(MotionEvent.ACTION_MOVE, 0, xTouch, yTouch);  
  1214.   
  1215.             // No volume/brightness action if coef < 2 or a secondary display is connected  
  1216.             //TODO : Volume action when a secondary display is connected  
  1217.             if (coef > 2 && mPresentation == null) {  
  1218.                 // Volume (Up or Down - Right side)  
  1219.                 if (!mEnableBrightnessGesture || (int)mTouchX > (screen.widthPixels / 2)){  
  1220.                     doVolumeTouch(y_changed);  
  1221.                 }  
  1222.                 // Brightness (Up or Down - Left side)  
  1223.                 if (mEnableBrightnessGesture && (int)mTouchX < (screen.widthPixels / 2)){  
  1224.                     doBrightnessTouch(y_changed);  
  1225.                 }  
  1226.                 // Extend the overlay for a little while, so that it doesn't  
  1227.                 // disappear on the user if more adjustment is needed. This  
  1228.                 // is because on devices with soft navigation (e.g. Galaxy  
  1229.                 // Nexus), gestures can't be made without activating the UI.  
  1230.                 if(AndroidDevices.hasNavBar())  
  1231.                     showOverlay();  
  1232.             }  
  1233.             // Seek (Right or Left move)  
  1234.             doSeekTouch(coef, xgesturesize, false);  
  1235.             break;  
  1236.   
  1237.         case MotionEvent.ACTION_UP:  
  1238.             // Mouse events for the core  
  1239.             LibVLC.sendMouseEvent(MotionEvent.ACTION_UP, 0, xTouch, yTouch);  
  1240.   
  1241.             // Audio or Brightness  
  1242.             if ( mTouchAction == TOUCH_NONE) {  
  1243.                 if (!mShowing) {  
  1244.                     showOverlay();  
  1245.                 } else {  
  1246.                     hideOverlay(true);  
  1247.                 }  
  1248.             }  
  1249.             // Seek  
  1250.             doSeekTouch(coef, xgesturesize, true);  
  1251.             break;  
  1252.         }  
  1253.         return mTouchAction != TOUCH_NONE;  
  1254.     }  
  1255.   
  1256.     private void doSeekTouch(float coef, float gesturesize, boolean seek) {  
  1257.         // No seek action if coef > 0.5 and gesturesize < 1cm  
  1258.         if (coef > 0.5 || Math.abs(gesturesize) < 1 || !mCanSeek)  
  1259.             return;  
  1260.   
  1261.         if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_SEEK)  
  1262.             return;  
  1263.         mTouchAction = TOUCH_SEEK;  
  1264.   
  1265.         // Always show seekbar when searching  
  1266.         if (!mShowing) showOverlay();  
  1267.   
  1268.         long length = mLibVLC.getLength();  
  1269.         long time = mLibVLC.getTime();  
  1270.   
  1271.         // Size of the jump, 10 minutes max (600000), with a bi-cubic progression, for a 8cm gesture  
  1272.         int jump = (int) (Math.signum(gesturesize) * ((600000 * Math.pow((gesturesize / 8), 4)) + 3000));  
  1273.   
  1274.         // Adjust the jump  
  1275.         if ((jump > 0) && ((time + jump) > length))  
  1276.             jump = (int) (length - time);  
  1277.         if ((jump < 0) && ((time + jump) < 0))  
  1278.             jump = (int) -time;  
  1279.   
  1280.         //Jump !  
  1281.         if (seek && length > 0)  
  1282.             mLibVLC.setTime(time + jump);  
  1283.   
  1284.         if (length > 0)  
  1285.             //Show the jump's size  
  1286.             showInfo(String.format("%s%s (%s)",  
  1287.                     jump >= 0 ? "+" : "",  
  1288.                     Strings.millisToString(jump),  
  1289.                     Strings.millisToString(time + jump)), 1000);  
  1290.         else  
  1291.             showInfo(R.string.unseekable_stream, 1000);  
  1292.     }  
  1293.   
  1294.     private void doVolumeTouch(float y_changed) {  
  1295.         if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_VOLUME)  
  1296.             return;  
  1297.         int delta = -(int) ((y_changed / mSurfaceYDisplayRange) * mAudioMax);  
  1298.         int vol = (int) Math.min(Math.max(mVol + delta, 0), mAudioMax);  
  1299.         if (delta != 0) {  
  1300.             mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, vol, 0);  
  1301.             mTouchAction = TOUCH_VOLUME;  
  1302.             showInfo(getString(R.string.volume) + '\u00A0' + Integer.toString(vol),1000);  
  1303.         }  
  1304.     }  
  1305.   
  1306.     private void initBrightnessTouch() {  
  1307.         float brightnesstemp = 0.01f;  
  1308.         // Initialize the layoutParams screen brightness  
  1309.         try {  
  1310.             brightnesstemp = android.provider.Settings.System.getInt(getContentResolver(),  
  1311.                     android.provider.Settings.System.SCREEN_BRIGHTNESS) / 255.0f;  
  1312.         } catch (SettingNotFoundException e) {  
  1313.             // TODO Auto-generated catch block  
  1314.             e.printStackTrace();  
  1315.         }  
  1316.         WindowManager.LayoutParams lp = getWindow().getAttributes();  
  1317.         lp.screenBrightness = brightnesstemp;  
  1318.         getWindow().setAttributes(lp);  
  1319.         mIsFirstBrightnessGesture = false;  
  1320.     }  
  1321.   
  1322.     private void doBrightnessTouch(float y_changed) {  
  1323.         if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_BRIGHTNESS)  
  1324.             return;  
  1325.         if (mIsFirstBrightnessGesture) initBrightnessTouch();  
  1326.         mTouchAction = TOUCH_BRIGHTNESS;  
  1327.   
  1328.         // Set delta : 0.07f is arbitrary for now, it possibly will change in the future  
  1329.         float delta = - y_changed / mSurfaceYDisplayRange * 0.07f;  
  1330.   
  1331.         // Estimate and adjust Brightness  
  1332.         WindowManager.LayoutParams lp = getWindow().getAttributes();  
  1333.         lp.screenBrightness =  Math.min(Math.max(lp.screenBrightness + delta, 0.01f), 1);  
  1334.   
  1335.         // Set Brightness  
  1336.         getWindow().setAttributes(lp);  
  1337.         showInfo(getString(R.string.brightness) + '\u00A0' + Math.round(lp.screenBrightness*15),1000);  
  1338.     }  
  1339.   
  1340.     /** 
  1341.      * handle changes of the seekbar (slicer) 
  1342.      */  
  1343.     private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {  
  1344.   
  1345.         @Override  
  1346.         public void onStartTrackingTouch(SeekBar seekBar) {  
  1347.             mDragging = true;  
  1348.             showOverlay(OVERLAY_INFINITE);  
  1349.         }  
  1350.   
  1351.         @Override  
  1352.         public void onStopTrackingTouch(SeekBar seekBar) {  
  1353.             mDragging = false;  
  1354.             showOverlay();  
  1355.             hideInfo();  
  1356.         }  
  1357.   
  1358.         @Override  
  1359.         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {  
  1360.             if (fromUser && mCanSeek) {  
  1361.                 mLibVLC.setTime(progress);  
  1362.                 setOverlayProgress();  
  1363.                 mTime.setText(Strings.millisToString(progress));  
  1364.                 showInfo(Strings.millisToString(progress));  
  1365.             }  
  1366.   
  1367.         }  
  1368.     };  
  1369.   
  1370.     /** 
  1371.     * 
  1372.     */  
  1373.     private final OnClickListener mAudioTrackListener = new OnClickListener() {  
  1374.         @Override  
  1375.         public void onClick(View v) {  
  1376.             final String[] arrList = new String[mAudioTracksList.size()];  
  1377.             int i = 0;  
  1378.             int listPosition = 0;  
  1379.             for(Map.Entry<Integer,String> entry : mAudioTracksList.entrySet()) {  
  1380.                 arrList[i] = entry.getValue();  
  1381.                 // map the track position to the list position  
  1382.                 if(entry.getKey() == mLibVLC.getAudioTrack())  
  1383.                     listPosition = i;  
  1384.                 i++;  
  1385.             }  
  1386.             AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)  
  1387.             .setTitle(R.string.track_audio)  
  1388.             .setSingleChoiceItems(arrList, listPosition, new DialogInterface.OnClickListener() {  
  1389.                 @Override  
  1390.                 public void onClick(DialogInterface dialog, int listPosition) {  
  1391.                     int trackID = -1;  
  1392.                     // Reverse map search...  
  1393.                     for(Map.Entry<Integer, String> entry : mAudioTracksList.entrySet()) {  
  1394.                         if(arrList[listPosition].equals(entry.getValue())) {  
  1395.                             trackID = entry.getKey();  
  1396.                             break;  
  1397.                         }  
  1398.                     }  
  1399.                     if(trackID < 0return;  
  1400.   
  1401.                     MediaDatabase.getInstance().updateMedia(  
  1402.                             mLocation,  
  1403.                             MediaDatabase.mediaColumn.MEDIA_AUDIOTRACK,  
  1404.                             trackID);  
  1405.                     mLibVLC.setAudioTrack(trackID);  
  1406.                     dialog.dismiss();  
  1407.                 }  
  1408.             })  
  1409.             .create();  
  1410.             dialog.setCanceledOnTouchOutside(true);  
  1411.             dialog.setOwnerActivity(VideoPlayerActivity.this);  
  1412.             dialog.show();  
  1413.         }  
  1414.     };  
  1415.   
  1416.     /** 
  1417.     * 
  1418.     */  
  1419.     private final OnClickListener mSubtitlesListener = new OnClickListener() {  
  1420.         @Override  
  1421.         public void onClick(View v) {  
  1422.             final String[] arrList = new String[mSubtitleTracksList.size()];  
  1423.             int i = 0;  
  1424.             int listPosition = 0;  
  1425.             for(Map.Entry<Integer,String> entry : mSubtitleTracksList.entrySet()) {  
  1426.                 arrList[i] = entry.getValue();  
  1427.                 // map the track position to the list position  
  1428.                 if(entry.getKey() == mLibVLC.getSpuTrack())  
  1429.                     listPosition = i;  
  1430.                 i++;  
  1431.             }  
  1432.   
  1433.             AlertDialog dialog = new AlertDialog.Builder(VideoPlayerActivity.this)  
  1434.             .setTitle(R.string.track_text)  
  1435.             .setSingleChoiceItems(arrList, listPosition, new DialogInterface.OnClickListener() {  
  1436.                 @Override  
  1437.                 public void onClick(DialogInterface dialog, int listPosition) {  
  1438.                     int trackID = -2;  
  1439.                     // Reverse map search...  
  1440.                     for(Map.Entry<Integer, String> entry : mSubtitleTracksList.entrySet()) {  
  1441.                         if(arrList[listPosition].equals(entry.getValue())) {  
  1442.                             trackID = entry.getKey();  
  1443.                             break;  
  1444.                         }  
  1445.                     }  
  1446.                     if(trackID < -1return;  
  1447.   
  1448.                     MediaDatabase.getInstance().updateMedia(  
  1449.                             mLocation,  
  1450.                             MediaDatabase.mediaColumn.MEDIA_SPUTRACK,  
  1451.                             trackID);  
  1452.                     mLibVLC.setSpuTrack(trackID);  
  1453.                     dialog.dismiss();  
  1454.                 }  
  1455.             })  
  1456.             .create();  
  1457.             dialog.setCanceledOnTouchOutside(true);  
  1458.             dialog.setOwnerActivity(VideoPlayerActivity.this);  
  1459.             dialog.show();  
  1460.         }  
  1461.     };  
  1462.   
  1463.     private final OnClickListener mNavMenuListener = new OnClickListener() {  
  1464.         @Override  
  1465.         public void onClick(View v) {  
  1466.             /* Try to return to the menu. */  
  1467.             /* FIXME: not working correctly in all cases */  
  1468.             mLibVLC.setTitle(0);  
  1469.         }  
  1470.     };  
  1471.   
  1472.     /** 
  1473.     * 
  1474.     */  
  1475.     private final OnClickListener mPlayPauseListener = new OnClickListener() {  
  1476.         @Override  
  1477.         public void onClick(View v) {  
  1478.             if (mLibVLC.isPlaying())  
  1479.                 pause();  
  1480.             else  
  1481.                 play();  
  1482.             showOverlay();  
  1483.         }  
  1484.     };  
  1485.   
  1486.     /** 
  1487.     * 
  1488.     */  
  1489.     private final OnClickListener mBackwardListener = new OnClickListener() {  
  1490.         @Override  
  1491.         public void onClick(View v) {  
  1492.             seek(-10000);  
  1493.         }  
  1494.     };  
  1495.   
  1496.     /** 
  1497.     * 
  1498.     */  
  1499.     private final OnClickListener mForwardListener = new OnClickListener() {  
  1500.         @Override  
  1501.         public void onClick(View v) {  
  1502.             seek(10000);  
  1503.         }  
  1504.     };  
  1505.   
  1506.     public void seek(int delta) {  
  1507.         // unseekable stream  
  1508.         if(mLibVLC.getLength() <= 0 || !mCanSeek) return;  
  1509.   
  1510.         long position = mLibVLC.getTime() + delta;  
  1511.         if (position < 0) position = 0;  
  1512.         mLibVLC.setTime(position);  
  1513.         showOverlay();  
  1514.     }  
  1515.   
  1516.     /** 
  1517.      * 
  1518.      */  
  1519.     private final OnClickListener mLockListener = new OnClickListener() {  
  1520.   
  1521.         @Override  
  1522.         public void onClick(View v) {  
  1523.             if (mIsLocked) {  
  1524.                 mIsLocked = false;  
  1525.                 unlockScreen();  
  1526.             } else {  
  1527.                 mIsLocked = true;  
  1528.                 lockScreen();  
  1529.             }  
  1530.         }  
  1531.     };  
  1532.   
  1533.     /** 
  1534.      * 
  1535.      */  
  1536.     private final OnClickListener mSizeListener = new OnClickListener() {  
  1537.   
  1538.         @Override  
  1539.         public void onClick(View v) {  
  1540.   
  1541.             if (mCurrentSize < SURFACE_ORIGINAL) {  
  1542.                 mCurrentSize++;  
  1543.             } else {  
  1544.                 mCurrentSize = 0;  
  1545.             }  
  1546.             changeSurfaceSize();  
  1547.             switch (mCurrentSize) {  
  1548.                 case SURFACE_BEST_FIT:  
  1549.                     showInfo(R.string.surface_best_fit, 1000);  
  1550.                     break;  
  1551.                 case SURFACE_FIT_HORIZONTAL:  
  1552.                     showInfo(R.string.surface_fit_horizontal, 1000);  
  1553.                     break;  
  1554.                 case SURFACE_FIT_VERTICAL:  
  1555.                     showInfo(R.string.surface_fit_vertical, 1000);  
  1556.                     break;  
  1557.                 case SURFACE_FILL:  
  1558.                     showInfo(R.string.surface_fill, 1000);  
  1559.                     break;  
  1560.                 case SURFACE_16_9:  
  1561.                     showInfo("16:9"1000);  
  1562.                     break;  
  1563.                 case SURFACE_4_3:  
  1564.                     showInfo("4:3"1000);  
  1565.                     break;  
  1566.                 case SURFACE_ORIGINAL:  
  1567.                     showInfo(R.string.surface_original, 1000);  
  1568.                     break;  
  1569.             }  
  1570.             showOverlay();  
  1571.         }  
  1572.     };  
  1573.   
  1574.     private final OnClickListener mRemainingTimeListener = new OnClickListener() {  
  1575.         @Override  
  1576.         public void onClick(View v) {  
  1577.             mDisplayRemainingTime = !mDisplayRemainingTime;  
  1578.             showOverlay();  
  1579.         }  
  1580.     };  
  1581.   
  1582.     /** 
  1583.      * attach and disattach surface to the lib 
  1584.      */  
  1585.     private final SurfaceHolder.Callback mSurfaceCallback = new Callback() {  
  1586.         @Override  
  1587.         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
  1588.             if(format == PixelFormat.RGBX_8888)  
  1589.                 Log.d(TAG, "Pixel format is RGBX_8888");  
  1590.             else if(format == PixelFormat.RGB_565)  
  1591.                 Log.d(TAG, "Pixel format is RGB_565");  
  1592.             else if(format == ImageFormat.YV12)  
  1593.                 Log.d(TAG, "Pixel format is YV12");  
  1594.             else  
  1595.                 Log.d(TAG, "Pixel format is other/unknown");  
  1596.             if(mLibVLC != null)  
  1597.                 mLibVLC.attachSurface(holder.getSurface(), VideoPlayerActivity.this);  
  1598.         }  
  1599.   
  1600.         @Override  
  1601.         public void surfaceCreated(SurfaceHolder holder) {  
  1602.         }  
  1603.   
  1604.         @Override  
  1605.         public void surfaceDestroyed(SurfaceHolder holder) {  
  1606.             if(mLibVLC != null)  
  1607.                 mLibVLC.detachSurface();  
  1608.         }  
  1609.     };  
  1610.   
  1611.     private final SurfaceHolder.Callback mSubtitlesSurfaceCallback = new Callback() {  
  1612.         @Override  
  1613.         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
  1614.             if(mLibVLC != null)  
  1615.                 mLibVLC.attachSubtitlesSurface(holder.getSurface());  
  1616.         }  
  1617.   
  1618.         @Override  
  1619.         public void surfaceCreated(SurfaceHolder holder) {  
  1620.         }  
  1621.   
  1622.         @Override  
  1623.         public void surfaceDestroyed(SurfaceHolder holder) {  
  1624.             if(mLibVLC != null)  
  1625.                 mLibVLC.detachSubtitlesSurface();  
  1626.         }  
  1627.     };  
  1628.   
  1629.     /** 
  1630.      * show overlay the the default timeout 
  1631.      */  
  1632.     private void showOverlay() {  
  1633.         showOverlay(OVERLAY_TIMEOUT);  
  1634.     }  
  1635.   
  1636.     /** 
  1637.      * show overlay 
  1638.      */  
  1639.     private void showOverlay(int timeout) {  
  1640.         if (mIsNavMenu)  
  1641.             return;  
  1642.         mHandler.sendEmptyMessage(SHOW_PROGRESS);  
  1643.         if (!mShowing) {  
  1644.             mShowing = true;  
  1645.             if (!mIsLocked) {  
  1646.                 mOverlayHeader.setVisibility(View.VISIBLE);  
  1647.                 mOverlayOption.setVisibility(View.VISIBLE);  
  1648.                 mPlayPause.setVisibility(View.VISIBLE);  
  1649.                 mMenu.setVisibility(View.VISIBLE);  
  1650.                 dimStatusBar(false);  
  1651.             }  
  1652.             mOverlayProgress.setVisibility(View.VISIBLE);  
  1653.             if (mPresentation != null) mOverlayBackground.setVisibility(View.VISIBLE);  
  1654.         }  
  1655.         Message msg = mHandler.obtainMessage(FADE_OUT);  
  1656.         if (timeout != 0) {  
  1657.             mHandler.removeMessages(FADE_OUT);  
  1658.             mHandler.sendMessageDelayed(msg, timeout);  
  1659.         }  
  1660.         updateOverlayPausePlay();  
  1661.     }  
  1662.   
  1663.   
  1664.     /** 
  1665.      * hider overlay 
  1666.      */  
  1667.     private void hideOverlay(boolean fromUser) {  
  1668.         if (mShowing) {  
  1669.             mHandler.removeMessages(SHOW_PROGRESS);  
  1670.             Log.i(TAG, "remove View!");  
  1671.             if (mOverlayTips != null) mOverlayTips.setVisibility(View.INVISIBLE);  
  1672.             if (!fromUser && !mIsLocked) {  
  1673.                 mOverlayHeader.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));  
  1674.                 mOverlayOption.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));  
  1675.                 mOverlayProgress.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));  
  1676.                 mPlayPause.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));  
  1677.                 mMenu.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));  
  1678.             }  
  1679.             if (mPresentation != null) {  
  1680.                 mOverlayBackground.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));  
  1681.                 mOverlayBackground.setVisibility(View.INVISIBLE);  
  1682.             }  
  1683.             mOverlayHeader.setVisibility(View.INVISIBLE);  
  1684.             mOverlayOption.setVisibility(View.INVISIBLE);  
  1685.             mOverlayProgress.setVisibility(View.INVISIBLE);  
  1686.             mPlayPause.setVisibility(View.INVISIBLE);  
  1687.             mMenu.setVisibility(View.INVISIBLE);  
  1688.             mShowing = false;  
  1689.             dimStatusBar(true);  
  1690.         }  
  1691.     }  
  1692.   
  1693.     /** 
  1694.      * Dim the status bar and/or navigation icons when needed on Android 3.x. 
  1695.      * Hide it on Android 4.0 and later 
  1696.      */  
  1697.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN)  
  1698.     private void dimStatusBar(boolean dim) {  
  1699.         if (!LibVlcUtil.isHoneycombOrLater() || !AndroidDevices.hasNavBar() || mIsNavMenu)  
  1700.             return;  
  1701.         int layout = 0;  
  1702.         if (!AndroidDevices.hasCombBar() && LibVlcUtil.isJellyBeanOrLater())  
  1703.             layout = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;  
  1704.         int visibility =  (dim ? (AndroidDevices.hasCombBar()  
  1705.                 ? View.SYSTEM_UI_FLAG_LOW_PROFILE  
  1706.                         : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)  
  1707.                         : View.SYSTEM_UI_FLAG_VISIBLE) | layout;  
  1708.         mSurface.setSystemUiVisibility(visibility);  
  1709.         mSubtitlesSurface.setSystemUiVisibility(visibility);  
  1710.     }  
  1711.   
  1712.     private void updateOverlayPausePlay() {  
  1713.         if (mLibVLC == null)  
  1714.             return;  
  1715.   
  1716.         if (mPresentation == null)  
  1717.             mPlayPause.setBackgroundResource(mLibVLC.isPlaying() ? R.drawable.ic_pause_circle  
  1718.                             : R.drawable.ic_play_circle);  
  1719.         else  
  1720.             mPlayPause.setBackgroundResource(mLibVLC.isPlaying() ? R.drawable.ic_pause_circle_big_o  
  1721.                             : R.drawable.ic_play_circle_big_o);  
  1722.     }  
  1723.   
  1724.     /** 
  1725.      * update the overlay 
  1726.      */  
  1727.     private int setOverlayProgress() {  
  1728.         if (mLibVLC == null) {  
  1729.             return 0;  
  1730.         }  
  1731.         int time = (int) mLibVLC.getTime();  
  1732.         int length = (int) mLibVLC.getLength();  
  1733.         if (length == 0) {  
  1734.             Media media = MediaDatabase.getInstance().getMedia(mLocation);  
  1735.             if (media != null)  
  1736.                 length = (int) media.getLength();  
  1737.         }  
  1738.   
  1739.         // Update all view elements  
  1740.         boolean isSeekable = mEnableJumpButtons && length > 0;  
  1741.         mBackward.setVisibility(isSeekable ? View.VISIBLE : View.GONE);  
  1742.         mForward.setVisibility(isSeekable ? View.VISIBLE : View.GONE);  
  1743.         mSeekbar.setMax(length);  
  1744.         mSeekbar.setProgress(time);  
  1745.         mSysTime.setText(DateFormat.getTimeFormat(this).format(new Date(System.currentTimeMillis())));  
  1746.         if (time >= 0) mTime.setText(Strings.millisToString(time));  
  1747.         if (length >= 0) mLength.setText(mDisplayRemainingTime && length > 0  
  1748.                 ? "- " + Strings.millisToString(length - time)  
  1749.                 : Strings.millisToString(length));  
  1750.   
  1751.         return time;  
  1752.     }  
  1753.   
  1754.     private void setESTracks() {  
  1755.         if (mLastAudioTrack >= 0) {  
  1756.             mLibVLC.setAudioTrack(mLastAudioTrack);  
  1757.             mLastAudioTrack = -1;  
  1758.         }  
  1759.         if (mLastSpuTrack >= -1) {  
  1760.             mLibVLC.setSpuTrack(mLastSpuTrack);  
  1761.             mLastSpuTrack = -2;  
  1762.         }  
  1763.     }  
  1764.   
  1765.     private void setESTrackLists(boolean force) {  
  1766.         if(mAudioTracksList == null || force) {  
  1767.             if (mLibVLC.getAudioTracksCount() > 2) {  
  1768.                 mAudioTracksList = mLibVLC.getAudioTrackDescription();  
  1769.                 mAudioTrack.setOnClickListener(mAudioTrackListener);  
  1770.                 mAudioTrack.setVisibility(View.VISIBLE);  
  1771.             }  
  1772.             else {  
  1773.                 mAudioTrack.setVisibility(View.GONE);  
  1774.                 mAudioTrack.setOnClickListener(null);  
  1775.             }  
  1776.         }  
  1777.         if (mSubtitleTracksList == null || force) {  
  1778.             if (mLibVLC.getSpuTracksCount() > 0) {  
  1779.                 mSubtitleTracksList = mLibVLC.getSpuTrackDescription();  
  1780.                 mSubtitle.setOnClickListener(mSubtitlesListener);  
  1781.                 mSubtitle.setVisibility(View.VISIBLE);  
  1782.             }  
  1783.             else {  
  1784.                 mSubtitle.setVisibility(View.GONE);  
  1785.                 mSubtitle.setOnClickListener(null);  
  1786.             }  
  1787.         }  
  1788.     }  
  1789.   
  1790.   
  1791.     /** 
  1792.      * 
  1793.      */  
  1794.     private void play() {  
  1795.         mLibVLC.play();  
  1796.         mSurface.setKeepScreenOn(true);  
  1797.     }  
  1798.   
  1799.     /** 
  1800.      * 
  1801.      */  
  1802.     private void pause() {  
  1803.         mLibVLC.pause();  
  1804.         mSurface.setKeepScreenOn(false);  
  1805.     }  
  1806.   
  1807.     /** 
  1808.      * External extras: 
  1809.      * - position (long) - position of the video to start with (in ms) 
  1810.      */  
  1811.     @SuppressWarnings({ "unchecked" })  
  1812.     private void loadMedia() {  
  1813.         mLocation = null;  
  1814.         String title = getResources().getString(R.string.title);  
  1815.         boolean dontParse = false;  
  1816.         boolean fromStart = false;  
  1817.         String itemTitle = null;  
  1818.         int itemPosition = -1// Index in the media list as passed by AudioServer (used only for vout transition internally)  
  1819.         long intentPosition = -1// position passed in by intent (ms)  
  1820.   
  1821.         if (getIntent().getAction() != null  
  1822.                 && getIntent().getAction().equals(Intent.ACTION_VIEW)) {  
  1823.             /* Started from external application 'content' */  
  1824.             if (getIntent().getData() != null  
  1825.                     && getIntent().getData().getScheme() != null  
  1826.                     && getIntent().getData().getScheme().equals("content")) {  
  1827.   
  1828.                 // Media or MMS URI  
  1829.                 if(getIntent().getData().getHost().equals("media")  
  1830.                         || getIntent().getData().getHost().equals("mms")) {  
  1831.                     try {  
  1832.                         Cursor cursor = getContentResolver().query(getIntent().getData(),  
  1833.                                 new String[]{ MediaStore.Video.Media.DATA }, nullnullnull);  
  1834.                         if (cursor != null) {  
  1835.                             int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);  
  1836.                             if (cursor.moveToFirst())  
  1837.                                 mLocation = LibVLC.PathToURI(cursor.getString(column_index));  
  1838.                             cursor.close();  
  1839.                         }  
  1840.                     } catch (Exception e) {  
  1841.                         Log.e(TAG, "Couldn't read the file from media or MMS");  
  1842.                         encounteredError();  
  1843.                     }  
  1844.                 }  
  1845.   
  1846.                 // Mail-based apps - download the stream to a temporary file and play it  
  1847.                 else if(getIntent().getData().getHost().equals("com.fsck.k9.attachmentprovider")  
  1848.                        || getIntent().getData().getHost().equals("gmail-ls")) {  
  1849.                     try {  
  1850.                         Cursor cursor = getContentResolver().query(getIntent().getData(),  
  1851.                                 new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, nullnullnull);  
  1852.                         if (cursor != null) {  
  1853.                             cursor.moveToFirst();  
  1854.                             String filename = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));  
  1855.                             cursor.close();  
  1856.                             Log.i(TAG, "Getting file " + filename + " from content:// URI");  
  1857.   
  1858.                             InputStream is = getContentResolver().openInputStream(getIntent().getData());  
  1859.                             OutputStream os = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/Download/" + filename);  
  1860.                             byte[] buffer = new byte[1024];  
  1861.                             int bytesRead = 0;  
  1862.                             while((bytesRead = is.read(buffer)) >= 0) {  
  1863.                                 os.write(buffer, 0, bytesRead);  
  1864.                             }  
  1865.                             os.close();  
  1866.                             is.close();  
  1867.                             mLocation = LibVLC.PathToURI(Environment.getExternalStorageDirectory().getPath() + "/Download/" + filename);  
  1868.                         }  
  1869.                     } catch (Exception e) {  
  1870.                         Log.e(TAG, "Couldn't download file from mail URI");  
  1871.                         encounteredError();  
  1872.                     }  
  1873.                 }  
  1874.   
  1875.                 // other content-based URI (probably file pickers)  
  1876.                 else {  
  1877.                     mLocation = getIntent().getData().getPath();  
  1878.                 }  
  1879.             } /* External application */  
  1880.             else if (getIntent().getDataString() != null) {  
  1881.                 // Plain URI  
  1882.                 mLocation = getIntent().getDataString();  
  1883.                 // Remove VLC prefix if needed  
  1884.                 if (mLocation.startsWith("vlc://")) {  
  1885.                     mLocation = mLocation.substring(6);  
  1886.                 }  
  1887.                 // Decode URI  
  1888.                 if (!mLocation.contains("/")){  
  1889.                     try {  
  1890.                         mLocation = URLDecoder.decode(mLocation,"UTF-8");  
  1891.                     } catch (UnsupportedEncodingException e) {  
  1892.                         Log.w(TAG, "UnsupportedEncodingException while decoding MRL " + mLocation);  
  1893.                     }  
  1894.                 }  
  1895.             } else {  
  1896.                 Log.e(TAG, "Couldn't understand the intent");  
  1897.                 encounteredError();  
  1898.             }  
  1899.   
  1900.             // Try to get the position  
  1901.             if(getIntent().getExtras() != null)  
  1902.                 intentPosition = getIntent().getExtras().getLong("position", -1);  
  1903.         } /* ACTION_VIEW */  
  1904.         /* Started from VideoListActivity */  
  1905.         else if(getIntent().getAction() != null  
  1906.                 && getIntent().getAction().equals(PLAY_FROM_VIDEOGRID)  
  1907.                 && getIntent().getExtras() != null) {  
  1908.             mLocation = getIntent().getExtras().getString("itemLocation");  
  1909.             itemTitle = getIntent().getExtras().getString("itemTitle");  
  1910.             dontParse = getIntent().getExtras().getBoolean("dontParse");  
  1911.             fromStart = getIntent().getExtras().getBoolean("fromStart");  
  1912.             itemPosition = getIntent().getExtras().getInt("itemPosition", -1);  
  1913.         }  
  1914.   
  1915.         mSurface.setKeepScreenOn(true);  
  1916.   
  1917.         if(mLibVLC == null)  
  1918.             return;  
  1919.   
  1920.         /* WARNING: hack to avoid a crash in mediacodec on KitKat. 
  1921.          * Disable hardware acceleration if the media has a ts extension. */  
  1922.         if (mLocation != null && LibVlcUtil.isKitKatOrLater()) {  
  1923.             String locationLC = mLocation.toLowerCase(Locale.ENGLISH);  
  1924.             if (locationLC.endsWith(".ts")  
  1925.                 || locationLC.endsWith(".tts")  
  1926.                 || locationLC.endsWith(".m2t")  
  1927.                 || locationLC.endsWith(".mts")  
  1928.                 || locationLC.endsWith(".m2ts")) {  
  1929.                 mDisabledHardwareAcceleration = true;  
  1930.                 mPreviousHardwareAccelerationMode = mLibVLC.getHardwareAcceleration();  
  1931. //                mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);  
  1932.                 mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);  
  1933.             }  
  1934.         }  
  1935.         mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);  
  1936.         /* Start / resume playback */  
  1937.         if(dontParse && itemPosition >= 0) {  
  1938.             // Provided externally from AudioService  
  1939.             Log.d(TAG, "Continuing playback from AudioService at index " + itemPosition);  
  1940.             savedIndexPosition = itemPosition;  
  1941.             if(!mLibVLC.isPlaying()) {  
  1942.                 // AudioService-transitioned playback for item after sleep and resume  
  1943.                 mLibVLC.playIndex(savedIndexPosition);  
  1944.                 dontParse = false;  
  1945.             }  
  1946.             else {  
  1947.                 stopLoadingAnimation();  
  1948.                 showOverlay();  
  1949.             }  
  1950.             updateNavStatus();  
  1951.         } else if (savedIndexPosition > -1) {  
  1952.             AudioServiceController.getInstance().stop(); // Stop the previous playback.  
  1953.             mLibVLC.setMediaList();  
  1954.             mLibVLC.playIndex(savedIndexPosition);  
  1955.         } else if (mLocation != null && mLocation.length() > 0 && !dontParse) {  
  1956.             AudioServiceController.getInstance().stop(); // Stop the previous playback.  
  1957.             mLibVLC.setMediaList();  
  1958.             mLibVLC.getMediaList().add(new Media(mLibVLC, mLocation));  
  1959.             savedIndexPosition = mLibVLC.getMediaList().size() - 1;  
  1960.             mLibVLC.playIndex(savedIndexPosition);  
  1961.         }  
  1962.         mCanSeek = false;  
  1963.   
  1964.         if (mLocation != null && mLocation.length() > 0 && !dontParse) {  
  1965.             // restore last position  
  1966.             Media media = MediaDatabase.getInstance().getMedia(mLocation);  
  1967.             if(media != null) {  
  1968.                 // in media library  
  1969.                 if(media.getTime() > 0 && !fromStart)  
  1970.                     mLibVLC.setTime(media.getTime());  
  1971.                 // Consume fromStart option after first use to prevent  
  1972.                 // restarting again when playback is paused.  
  1973.                 getIntent().putExtra("fromStart"false);  
  1974.   
  1975.                 mLastAudioTrack = media.getAudioTrack();  
  1976.                 mLastSpuTrack = media.getSpuTrack();  
  1977.             } else {  
  1978.                 // not in media library  
  1979.                 long rTime = mSettings.getLong(PreferencesActivity.VIDEO_RESUME_TIME, -1);  
  1980.                 Editor editor = mSettings.edit();  
  1981.                 editor.putLong(PreferencesActivity.VIDEO_RESUME_TIME, -1);  
  1982.                 editor.commit();  
  1983.                 if(rTime > 0)  
  1984.                     mLibVLC.setTime(rTime);  
  1985.   
  1986.                 if(intentPosition > 0)  
  1987.                     mLibVLC.setTime(intentPosition);  
  1988.             }  
  1989.   
  1990.             // Get possible subtitles  
  1991.             String subtitleList_serialized = mSettings.getString(PreferencesActivity.VIDEO_SUBTITLE_FILES, null);  
  1992.             ArrayList<String> prefsList = new ArrayList<String>();  
  1993.             if(subtitleList_serialized != null) {  
  1994.                 ByteArrayInputStream bis = new ByteArrayInputStream(subtitleList_serialized.getBytes());  
  1995.                 try {  
  1996.                     ObjectInputStream ois = new ObjectInputStream(bis);  
  1997.                     prefsList = (ArrayList<String>)ois.readObject();  
  1998.                 } catch(ClassNotFoundException e) {}  
  1999.                   catch (StreamCorruptedException e) {}  
  2000.                   catch (IOException e) {}  
  2001.             }  
  2002.             for(String x : prefsList){  
  2003.                 if(!mSubtitleSelectedFiles.contains(x))  
  2004.                     mSubtitleSelectedFiles.add(x);  
  2005.              }  
  2006.   
  2007.             // Get the title  
  2008.             try {  
  2009.                 title = URLDecoder.decode(mLocation, "UTF-8");  
  2010.             } catch (UnsupportedEncodingException e) {  
  2011.             } catch (IllegalArgumentException e) {  
  2012.             }  
  2013.             if (title.startsWith("file:")) {  
  2014.                 title = new File(title).getName();  
  2015.                 int dotIndex = title.lastIndexOf('.');  
  2016.                 if (dotIndex != -1)  
  2017.                     title = title.substring(0, dotIndex);  
  2018.             }  
  2019.         } else if(itemTitle != null) {  
  2020.             title = itemTitle;  
  2021.         }  
  2022.         mTitle.setText(title);  
  2023.     }  
  2024.   
  2025.     @SuppressWarnings("deprecation")  
  2026.     private int getScreenRotation(){  
  2027.         WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);  
  2028.         Display display = wm.getDefaultDisplay();  
  2029.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO /* Android 2.2 has getRotation */) {  
  2030.             try {  
  2031.                 Method m = display.getClass().getDeclaredMethod("getRotation");  
  2032.                 return (Integer) m.invoke(display);  
  2033.             } catch (Exception e) {  
  2034.                 return Surface.ROTATION_0;  
  2035.             }  
  2036.         } else {  
  2037.             return display.getOrientation();  
  2038.         }  
  2039.     }  
  2040.   
  2041.     @TargetApi(Build.VERSION_CODES.GINGERBREAD)  
  2042.     private int getScreenOrientation(){  
  2043.         WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);  
  2044.         Display display = wm.getDefaultDisplay();  
  2045.         int rot = getScreenRotation();  
  2046.         /* 
  2047.          * Since getRotation() returns the screen's "natural" orientation, 
  2048.          * which is not guaranteed to be SCREEN_ORIENTATION_PORTRAIT, 
  2049.          * we have to invert the SCREEN_ORIENTATION value if it is "naturally" 
  2050.          * landscape. 
  2051.          */  
  2052.         @SuppressWarnings("deprecation")  
  2053.         boolean defaultWide = display.getWidth() > display.getHeight();  
  2054.         if(rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270)  
  2055.             defaultWide = !defaultWide;  
  2056.         if(defaultWide) {  
  2057.             switch (rot) {  
  2058.             case Surface.ROTATION_0:  
  2059.                 return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;  
  2060.             case Surface.ROTATION_90:  
  2061.                 return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;  
  2062.             case Surface.ROTATION_180:  
  2063.                 // SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API  
  2064.                 // Level 9+  
  2065.                 return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE  
  2066.                         : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  
  2067.             case Surface.ROTATION_270:  
  2068.                 // SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API  
  2069.                 // Level 9+  
  2070.                 return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT  
  2071.                         : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  
  2072.             default:  
  2073.                 return 0;  
  2074.             }  
  2075.         } else {  
  2076.             switch (rot) {  
  2077.             case Surface.ROTATION_0:  
  2078.                 return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;  
  2079.             case Surface.ROTATION_90:  
  2080.                 return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;  
  2081.             case Surface.ROTATION_180:  
  2082.                 // SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API  
  2083.                 // Level 9+  
  2084.                 return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT  
  2085.                         : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  
  2086.             case Surface.ROTATION_270:  
  2087.                 // SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API  
  2088.                 // Level 9+  
  2089.                 return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE  
  2090.                         : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  
  2091.             default:  
  2092.                 return 0;  
  2093.             }  
  2094.         }  
  2095.     }  
  2096.   
  2097.     public void showAdvancedOptions(View v) {  
  2098.         CommonDialogs.advancedOptions(this, v, MenuType.Video);  
  2099.     }  
  2100.   
  2101.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  2102.     private void createPresentation() {  
  2103.         if (mMediaRouter == null || mEnableCloneMode)  
  2104.             return;  
  2105.   
  2106.         // Get the current route and its presentation display.  
  2107.         MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(  
  2108.             MediaRouter.ROUTE_TYPE_LIVE_VIDEO);  
  2109.   
  2110.         Display presentationDisplay = route != null ? route.getPresentationDisplay() : null;  
  2111.   
  2112.         if (presentationDisplay != null) {  
  2113.             // Show a new presentation if possible.  
  2114.             Log.i(TAG, "Showing presentation on display: " + presentationDisplay);  
  2115.             mPresentation = new SecondaryDisplay(this, presentationDisplay);  
  2116.             mPresentation.setOnDismissListener(mOnDismissListener);  
  2117.             try {  
  2118.                 mPresentation.show();  
  2119.             } catch (WindowManager.InvalidDisplayException ex) {  
  2120.                 Log.w(TAG, "Couldn't show presentation!  Display was removed in "  
  2121.                         + "the meantime.", ex);  
  2122.                 mPresentation = null;  
  2123.             }  
  2124.         } else  
  2125.             Log.i(TAG, "No secondary display detected");  
  2126.     }  
  2127.   
  2128.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  2129.     private void removePresentation() {  
  2130.         if (mMediaRouter == null)  
  2131.             return;  
  2132.   
  2133.         // Dismiss the current presentation if the display has changed.  
  2134.         Log.i(TAG, "Dismissing presentation because the current route no longer "  
  2135.                 + "has a presentation display.");  
  2136.         mLibVLC.pause(); // Stop sending frames to avoid a crash.  
  2137.         finish(); //TODO restore the video on the new display instead of closing  
  2138.         if (mPresentation != null) mPresentation.dismiss();  
  2139.         mPresentation = null;  
  2140.     }  
  2141.   
  2142.     /** 
  2143.      * Listens for when presentations are dismissed. 
  2144.      */  
  2145.     private final DialogInterface.OnDismissListener mOnDismissListener = new DialogInterface.OnDismissListener() {  
  2146.         @Override  
  2147.         public void onDismiss(DialogInterface dialog) {  
  2148.             if (dialog == mPresentation) {  
  2149.                 Log.i(TAG, "Presentation was dismissed.");  
  2150.                 mPresentation = null;  
  2151.             }  
  2152.         }  
  2153.     };  
  2154.   
  2155.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  2156.     private final class SecondaryDisplay extends Presentation {  
  2157.         public final static String TAG = "VLC/SecondaryDisplay";  
  2158.   
  2159.         private SurfaceView mSurface;  
  2160.         private SurfaceView mSubtitlesSurface;  
  2161.         private SurfaceHolder mSurfaceHolder;  
  2162.         private SurfaceHolder mSubtitlesSurfaceHolder;  
  2163.         private FrameLayout mSurfaceFrame;  
  2164.         private LibVLC mLibVLC;  
  2165.   
  2166.         public SecondaryDisplay(Context context, Display display) {  
  2167.             super(context, display);  
  2168.             if (context instanceof Activity) {  
  2169.                 setOwnerActivity((Activity) context);  
  2170.             }  
  2171.             try {  
  2172.                 mLibVLC = VLCInstance.getLibVlcInstance();  
  2173.             } catch (LibVlcException e) {  
  2174.                 Log.d(TAG, "LibVLC initialisation failed");  
  2175.                 return;  
  2176.             }  
  2177.         }  
  2178.   
  2179.         @Override  
  2180.         protected void onCreate(Bundle savedInstanceState) {  
  2181.             super.onCreate(savedInstanceState);  
  2182.             setContentView(R.layout.player_remote);  
  2183.   
  2184.             mSurface = (SurfaceView) findViewById(R.id.remote_player_surface);  
  2185.             mSurfaceHolder = mSurface.getHolder();  
  2186.             mSurfaceFrame = (FrameLayout) findViewById(R.id.remote_player_surface_frame);  
  2187.             String chroma = mSettings.getString("chroma_format""");  
  2188.             if(LibVlcUtil.isGingerbreadOrLater() && chroma.equals("YV12")) {  
  2189.                 mSurfaceHolder.setFormat(ImageFormat.YV12);  
  2190.             } else if (chroma.equals("RV16")) {  
  2191.                 mSurfaceHolder.setFormat(PixelFormat.RGB_565);  
  2192.             } else {  
  2193.                 mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);  
  2194.             }  
  2195.   
  2196.             VideoPlayerActivity activity = (VideoPlayerActivity)getOwnerActivity();  
  2197.             if (activity == null) {  
  2198.                 Log.e(TAG, "Failed to get the VideoPlayerActivity instance, secondary display won't work");  
  2199.                 return;  
  2200.             }  
  2201.   
  2202.             mSurfaceHolder.addCallback(activity.mSurfaceCallback);  
  2203.   
  2204.             mSubtitlesSurface = (SurfaceView) findViewById(R.id.remote_subtitles_surface);  
  2205.             mSubtitlesSurfaceHolder = mSubtitlesSurface.getHolder();  
  2206.             mSubtitlesSurfaceHolder.setFormat(PixelFormat.RGBA_8888);  
  2207.             mSubtitlesSurface.setZOrderMediaOverlay(true);  
  2208.             mSubtitlesSurfaceHolder.addCallback(activity.mSubtitlesSurfaceCallback);  
  2209.   
  2210.             /* Only show the subtitles surface when using "Full Acceleration" mode */  
  2211.             if (mLibVLC != null && mLibVLC.getHardwareAcceleration() == LibVLC.HW_ACCELERATION_FULL)  
  2212.                 mSubtitlesSurface.setVisibility(View.VISIBLE);  
  2213.             Log.i(TAG, "Secondary display created");  
  2214.         }  
  2215.     }  
  2216.   
  2217.     /** 
  2218.      * Start the video loading animation. 
  2219.      */  
  2220.     private void startLoadingAnimation() {  
  2221.         AnimationSet anim = new AnimationSet(true);  
  2222.         RotateAnimation rotate = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);  
  2223.         rotate.setDuration(800);  
  2224.         rotate.setInterpolator(new DecelerateInterpolator());  
  2225.         rotate.setRepeatCount(RotateAnimation.INFINITE);  
  2226.         anim.addAnimation(rotate);  
  2227.         mLoading.startAnimation(anim);  
  2228.         mLoadingText.setVisibility(View.VISIBLE);  
  2229.     }  
  2230.   
  2231.     /** 
  2232.      * Stop the video loading animation. 
  2233.      */  
  2234.     private void stopLoadingAnimation() {  
  2235.         mLoading.setVisibility(View.INVISIBLE);  
  2236.         mLoading.clearAnimation();  
  2237.         mLoadingText.setVisibility(View.GONE);  
  2238.     }  
  2239.   
  2240.     public void onClickOverlayTips(View v) {  
  2241.         mOverlayTips.setVisibility(View.GONE);  
  2242.     }  
  2243.   
  2244.     public void onClickDismissTips(View v) {  
  2245.         mOverlayTips.setVisibility(View.GONE);  
  2246.         Editor editor = mSettings.edit();  
  2247.         editor.putBoolean(PREF_TIPS_SHOWN, true);  
  2248.         editor.commit();  
  2249.     }  
  2250.   
  2251.     private void updateNavStatus() {  
  2252.         mHasMenu = mLibVLC.getChapterCountForTitle(0) > 1 && mLibVLC.getTitleCount() > 1;  
  2253.         mIsNavMenu = mHasMenu && mLibVLC.getTitle() == 0;  
  2254.         /*** 
  2255.          * HACK ALERT: assume that any media with >1 titles = DVD with menus 
  2256.          * Should be replaced with a more robust title/chapter selection popup 
  2257.          */  
  2258.   
  2259.         Log.d(TAG,  
  2260.                 "updateNavStatus: getChapterCountForTitle(0) = "  
  2261.                         + mLibVLC.getChapterCountForTitle(0)  
  2262.                         + ", getTitleCount() = " + mLibVLC.getTitleCount());  
  2263.         if (mIsNavMenu) {  
  2264.             /* 
  2265.              * Keep the overlay hidden in order to have touch events directly 
  2266.              * transmitted to navigation handling. 
  2267.              */  
  2268.             hideOverlay(false);  
  2269.         }  
  2270.         else if (mHasMenu) {  
  2271.             setESTrackLists(true);  
  2272.             setESTracks();  
  2273.   
  2274.             /* Show the return to menu button. */  
  2275.             mNavMenu.setVisibility(View.VISIBLE);  
  2276.             mNavMenu.setOnClickListener(mNavMenuListener);  
  2277.         }  
  2278.         else  
  2279.             mNavMenu.setVisibility(View.GONE);  
  2280.   
  2281.     }  
  2282. }  

 

http://blog.csdn.net/cuiran/article/details/40558085

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics