[
  {
    "path": ".gitignore",
    "content": ".gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/.idea\n*.iml\n/gradle\ngradlew\ngradlew.bat\nproguard-rules.pro"
  },
  {
    "path": "README.md",
    "content": "vlc-android-demo\n================\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'android'\n\nandroid {\n    compileSdkVersion 19\n    buildToolsVersion \"19.1.0\"\n\n    defaultConfig {\n        applicationId \"com.nmbb.vlc\"\n        minSdkVersion 9\n        targetSdkVersion 19\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            runProguard false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:19.1.0'\n}\n"
  },
  {
    "path": "app/src/androidTest/java/com/nmbb/vlc/ApplicationTest.java",
    "content": "package com.nmbb.vlc;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.nmbb.vlc\">\n\n    <uses-sdk\n        android:minSdkVersion=\"9\"\n        android:targetSdkVersion=\"19\" />\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/app_icon\"\n        android:label=\"@string/app_name\"\n        android:name=\".VLCApplication\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".ui.VlcVideoActivity\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@style/VideoTheme\"\n            android:label=\"@string/app_name\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/nmbb/vlc/VLCApplication.java",
    "content": "package com.nmbb.vlc;\n\nimport android.app.Application;\nimport android.content.Context;\n\n/**\n * Created by tangjun on 14-8-24.\n */\npublic class VLCApplication extends Application {\n\n\tprivate static VLCApplication sInstance;\n\n\t@Override\n\tpublic void onCreate() {\n\t\tsuper.onCreate();\n\n\t\tsInstance = this;\n\t}\n\n\tpublic static Context getAppContext() {\n\t\treturn sInstance;\n\t}\n}\n"
  },
  {
    "path": "app/src/main/java/com/nmbb/vlc/ui/VlcVideoActivity.java",
    "content": "package com.nmbb.vlc.ui;\n\nimport android.app.Activity;\nimport android.content.res.Configuration;\nimport android.graphics.PixelFormat;\nimport android.media.AudioManager;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.nmbb.vlc.R;\n\nimport org.videolan.libvlc.EventHandler;\nimport org.videolan.libvlc.IVideoPlayer;\nimport org.videolan.libvlc.LibVLC;\nimport org.videolan.libvlc.LibVlcException;\nimport org.videolan.vlc.util.VLCInstance;\n\npublic class VlcVideoActivity extends Activity implements SurfaceHolder.Callback, IVideoPlayer {\n\n\tprivate final static String TAG = \"[VlcVideoActivity]\";\n\n\tprivate SurfaceView mSurfaceView;\n\tprivate LibVLC mMediaPlayer;\n\tprivate SurfaceHolder mSurfaceHolder;\n    \n    private View mLoadingView;\n\n\tprivate int mVideoHeight;\n\tprivate int mVideoWidth;\n\tprivate int mVideoVisibleHeight;\n\tprivate int mVideoVisibleWidth;\n\tprivate int mSarNum;\n\tprivate int mSarDen;\n\n\t@Override\n\tprotected void onCreate(Bundle savedInstanceState) {\n\t\tsuper.onCreate(savedInstanceState);\n\t\tsetContentView(R.layout.activity_video_vlc);\n\n\t\tmSurfaceView = (SurfaceView) findViewById(R.id.video);\n        mLoadingView = findViewById(R.id.video_loading);\n\t\ttry {\n\t\t\tmMediaPlayer = VLCInstance.getLibVlcInstance();\n\t\t} catch (LibVlcException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\tmSurfaceHolder = mSurfaceView.getHolder();\n\t\tmSurfaceHolder.setFormat(PixelFormat.RGBX_8888);\n\t\tmSurfaceHolder.addCallback(this);\n\n\t\tmMediaPlayer.eventVideoPlayerActivityCreated(true);\n\n\t\tEventHandler em = EventHandler.getInstance();\n\t\tem.addHandler(mVlcHandler);\n\n\t\tthis.setVolumeControlStream(AudioManager.STREAM_MUSIC);\n\t\tmSurfaceView.setKeepScreenOn(true);\n\t\t//\t\tmMediaPlayer.setMediaList();\n\t\t//\t\tmMediaPlayer.getMediaList().add(new Media(mMediaPlayer, \"http://live.3gv.ifeng.com/zixun.m3u8\"), false);\n\t\t//\t\tmMediaPlayer.playIndex(0);\n\t\tmMediaPlayer.playMRL(\"http://live.3gv.ifeng.com/zixun.m3u8\");\n\t}\n\n\t@Override\n\tpublic void onPause() {\n\t\tsuper.onPause();\n\n\t\tif (mMediaPlayer != null) {\n\t\t\tmMediaPlayer.stop();\n\t\t\tmSurfaceView.setKeepScreenOn(false);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onDestroy() {\n\t\tsuper.onDestroy();\n\t\tif (mMediaPlayer != null) {\n\t\t\tmMediaPlayer.eventVideoPlayerActivityCreated(false);\n\n\t\t\tEventHandler em = EventHandler.getInstance();\n\t\t\tem.removeHandler(mVlcHandler);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onConfigurationChanged(Configuration newConfig) {\n\t\tsetSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);\n\t\tsuper.onConfigurationChanged(newConfig);\n\t}\n\n\t@Override\n\tpublic void surfaceCreated(SurfaceHolder holder) {\n\t\tif (mMediaPlayer != null) {\n\t\t\tmSurfaceHolder = holder;\n\t\t\tmMediaPlayer.attachSurface(holder.getSurface(), this);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {\n\t\tmSurfaceHolder = holder;\n\t\tif (mMediaPlayer != null) {\n\t\t\tmMediaPlayer.attachSurface(holder.getSurface(), this);//, width, height\n\t\t}\n\t\tif (width > 0) {\n\t\t\tmVideoHeight = height;\n\t\t\tmVideoWidth = width;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void surfaceDestroyed(SurfaceHolder holder) {\n\t\tif (mMediaPlayer != null) {\n\t\t\tmMediaPlayer.detachSurface();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {\n\t\tmVideoHeight = height;\n\t\tmVideoWidth = width;\n\t\tmVideoVisibleHeight = visible_height;\n\t\tmVideoVisibleWidth = visible_width;\n\t\tmSarNum = sar_num;\n\t\tmSarDen = sar_den;\n\t\tmHandler.removeMessages(HANDLER_SURFACE_SIZE);\n\t\tmHandler.sendEmptyMessage(HANDLER_SURFACE_SIZE);\n\t}\n\n\tprivate static final int HANDLER_BUFFER_START = 1;\n\tprivate static final int HANDLER_BUFFER_END = 2;\n\tprivate static final int HANDLER_SURFACE_SIZE = 3;\n\n\tprivate static final int SURFACE_BEST_FIT = 0;\n\tprivate static final int SURFACE_FIT_HORIZONTAL = 1;\n\tprivate static final int SURFACE_FIT_VERTICAL = 2;\n\tprivate static final int SURFACE_FILL = 3;\n\tprivate static final int SURFACE_16_9 = 4;\n\tprivate static final int SURFACE_4_3 = 5;\n\tprivate static final int SURFACE_ORIGINAL = 6;\n\tprivate int mCurrentSize = SURFACE_BEST_FIT;\n\n\tprivate Handler mVlcHandler = new Handler() {\n\t\t@Override\n\t\tpublic void handleMessage(Message msg) {\n\t\t\tif (msg == null || msg.getData() == null)\n\t\t\t\treturn;\n\n\t\t\tswitch (msg.getData().getInt(\"event\")) {\n\t\t\tcase EventHandler.MediaPlayerTimeChanged:\n\t\t\t\tbreak;\n\t\t\tcase EventHandler.MediaPlayerPositionChanged:\n\t\t\t\tbreak;\n\t\t\tcase EventHandler.MediaPlayerPlaying:\n\t\t\t\tmHandler.removeMessages(HANDLER_BUFFER_END);\n\t\t\t\tmHandler.sendEmptyMessage(HANDLER_BUFFER_END);\n\t\t\t\tbreak;\n\t\t\tcase EventHandler.MediaPlayerBuffering:\n\t\t\t\tbreak;\n\t\t\tcase EventHandler.MediaPlayerLengthChanged:\n\t\t\t\tbreak;\n\t\t\tcase EventHandler.MediaPlayerEndReached:\n\t\t\t\t//播放完成\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\t};\n\n\tprivate Handler mHandler = new Handler() {\n\t\t@Override\n\t\tpublic void handleMessage(Message msg) {\n\t\t\tswitch (msg.what) {\n\t\t\tcase HANDLER_BUFFER_START:\n                showLoading();\n\t\t\t\tbreak;\n\t\t\tcase HANDLER_BUFFER_END:\n                hideLoading();\n\t\t\t\tbreak;\n\t\t\tcase HANDLER_SURFACE_SIZE:\n\t\t\t\tchangeSurfaceSize();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate void showLoading() {\n        mLoadingView.setVisibility(View.VISIBLE);\n\t}\n\n\tprivate void hideLoading() {\n        mLoadingView.setVisibility(View.GONE);\n\t}\n\n\tprivate void changeSurfaceSize() {\n\t\t// get screen size\n\t\tint dw = getWindowManager().getDefaultDisplay().getWidth();\n\t\tint dh = getWindowManager().getDefaultDisplay().getHeight();\n\n\t\t// calculate aspect ratio\n\t\tdouble ar = (double) mVideoWidth / (double) mVideoHeight;\n\t\t// calculate display aspect ratio\n\t\tdouble dar = (double) dw / (double) dh;\n\n\t\tswitch (mCurrentSize) {\n\t\tcase SURFACE_BEST_FIT:\n\t\t\tif (dar < ar)\n\t\t\t\tdh = (int) (dw / ar);\n\t\t\telse\n\t\t\t\tdw = (int) (dh * ar);\n\t\t\tbreak;\n\t\tcase SURFACE_FIT_HORIZONTAL:\n\t\t\tdh = (int) (dw / ar);\n\t\t\tbreak;\n\t\tcase SURFACE_FIT_VERTICAL:\n\t\t\tdw = (int) (dh * ar);\n\t\t\tbreak;\n\t\tcase SURFACE_FILL:\n\t\t\tbreak;\n\t\tcase SURFACE_16_9:\n\t\t\tar = 16.0 / 9.0;\n\t\t\tif (dar < ar)\n\t\t\t\tdh = (int) (dw / ar);\n\t\t\telse\n\t\t\t\tdw = (int) (dh * ar);\n\t\t\tbreak;\n\t\tcase SURFACE_4_3:\n\t\t\tar = 4.0 / 3.0;\n\t\t\tif (dar < ar)\n\t\t\t\tdh = (int) (dw / ar);\n\t\t\telse\n\t\t\t\tdw = (int) (dh * ar);\n\t\t\tbreak;\n\t\tcase SURFACE_ORIGINAL:\n\t\t\tdh = mVideoHeight;\n\t\t\tdw = mVideoWidth;\n\t\t\tbreak;\n\t\t}\n\n\t\tmSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);\n\t\tViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();\n\t\tlp.width = dw;\n\t\tlp.height = dh;\n\t\tmSurfaceView.setLayoutParams(lp);\n\t\tmSurfaceView.invalidate();\n\t}\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/AudioOutput.java",
    "content": "/*****************************************************************************\n * Aout.java\n *****************************************************************************\n * Copyright © 2011-2012 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\nimport android.media.AudioFormat;\nimport android.media.AudioManager;\nimport android.media.AudioTrack;\nimport android.util.Log;\n\npublic class AudioOutput {\n    /**\n     * Java side of the audio output module for Android.\n     * Uses an AudioTrack to play decoded audio buffers.\n     *\n     * TODO Use MODE_STATIC instead of MODE_STREAM with a MemoryFile (ashmem)\n     */\n\n    public AudioOutput() {\n    }\n\n    private AudioTrack mAudioTrack;\n    private static final String TAG = \"LibVLC/aout\";\n\n    public void init(int sampleRateInHz, int channels, int samples) {\n        Log.d(TAG, sampleRateInHz + \", \" + channels + \", \" + samples + \"=>\" + channels * samples);\n        int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz,\n                                                        AudioFormat.CHANNEL_OUT_STEREO,\n                                                        AudioFormat.ENCODING_PCM_16BIT);\n        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,\n                                     sampleRateInHz,\n                                     AudioFormat.CHANNEL_OUT_STEREO,\n                                     AudioFormat.ENCODING_PCM_16BIT,\n                                     Math.max(minBufferSize, channels * samples * 2),\n                                     AudioTrack.MODE_STREAM);\n    }\n\n    public void release() {\n        if (mAudioTrack != null) {\n            mAudioTrack.release();\n        }\n        mAudioTrack = null;\n    }\n\n    public void playBuffer(byte[] audioData, int bufferSize) {\n        if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED)\n            return;\n        if (mAudioTrack.write(audioData, 0, bufferSize) != bufferSize) {\n            Log.w(TAG, \"Could not write all the samples to the audio device\");\n        }\n        mAudioTrack.play();\n    }\n\n    public void pause() {\n        mAudioTrack.pause();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/EventHandler.java",
    "content": "/*****************************************************************************\n * EventHandler.java\n *****************************************************************************\n * Copyright © 2011-2014 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Message;\n\nimport java.util.ArrayList;\n\npublic class EventHandler {\n\n    /*\n     * Be sure to subscribe to events you need in the JNI too.\n     */\n\n    //public static final int MediaMetaChanged                = 0;\n    //public static final int MediaSubItemAdded               = 1;\n    //public static final int MediaDurationChanged            = 2;\n    public static final int MediaParsedChanged                = 3;\n    //public static final int MediaFreed                      = 4;\n    //public static final int MediaStateChanged               = 5;\n\n    //public static final int MediaPlayerMediaChanged         = 0x100;\n    //public static final int MediaPlayerNothingSpecial       = 0x101;\n    //public static final int MediaPlayerOpening              = 0x102;\n    public static final int MediaPlayerBuffering            = 0x103;\n    public static final int MediaPlayerPlaying                = 0x104;\n    public static final int MediaPlayerPaused                 = 0x105;\n    public static final int MediaPlayerStopped                = 0x106;\n    //public static final int MediaPlayerForward              = 0x107;\n    //public static final int MediaPlayerBackward             = 0x108;\n    public static final int MediaPlayerEndReached             = 0x109;\n    public static final int MediaPlayerEncounteredError       = 0x10a;\n    public static final int MediaPlayerTimeChanged            = 0x10b;\n    public static final int MediaPlayerPositionChanged        = 0x10c;\n    //public static final int MediaPlayerSeekableChanged      = 0x10d;\n    //public static final int MediaPlayerPausableChanged      = 0x10e;\n    //public static final int MediaPlayerTitleChanged         = 0x10f;\n    //public static final int MediaPlayerSnapshotTaken        = 0x110;\n    public static final int MediaPlayerLengthChanged        = 0x111;\n    public static final int MediaPlayerVout                   = 0x112;\n\n    //public static final int MediaListItemAdded              = 0x200;\n    //public static final int MediaListWillAddItem            = 0x201;\n    //public static final int MediaListItemDeleted            = 0x202;\n    //public static final int MediaListWillDeleteItem         = 0x203;\n\n    //public static final int MediaListViewItemAdded          = 0x300;\n    //public static final int MediaListViewWillAddItem        = 0x301;\n    //public static final int MediaListViewItemDeleted        = 0x302;\n    //public static final int MediaListViewWillDeleteItem     = 0x303;\n\n    //public static final int MediaListPlayerPlayed           = 0x400;\n    //public static final int MediaListPlayerNextItemSet      = 0x401;\n    //public static final int MediaListPlayerStopped          = 0x402;\n\n    //public static final int MediaDiscovererStarted          = 0x500;\n    //public static final int MediaDiscovererEnded            = 0x501;\n\n    //public static final int VlmMediaAdded                   = 0x600;\n    //public static final int VlmMediaRemoved                 = 0x601;\n    //public static final int VlmMediaChanged                 = 0x602;\n    //public static final int VlmMediaInstanceStarted         = 0x603;\n    //public static final int VlmMediaInstanceStopped         = 0x604;\n    //public static final int VlmMediaInstanceStatusInit      = 0x605;\n    //public static final int VlmMediaInstanceStatusOpening   = 0x606;\n    //public static final int VlmMediaInstanceStatusPlaying   = 0x607;\n    //public static final int VlmMediaInstanceStatusPause     = 0x608;\n    //public static final int VlmMediaInstanceStatusEnd       = 0x609;\n    //public static final int VlmMediaInstanceStatusError     = 0x60a;\n\n    public static final int CustomMediaListExpanding          = 0x2000;\n    public static final int CustomMediaListExpandingEnd       = 0x2001;\n    public static final int CustomMediaListItemAdded          = 0x2002;\n    public static final int CustomMediaListItemDeleted        = 0x2003;\n    public static final int CustomMediaListItemMoved          = 0x2004;\n\n    public static final int HardwareAccelerationError         = 0x3000;\n\n    private ArrayList<Handler> mEventHandler;\n    private static EventHandler mInstance;\n\n    EventHandler() {\n        mEventHandler = new ArrayList<Handler>();\n    }\n\n    public static EventHandler getInstance() {\n        if (mInstance == null) {\n            mInstance = new EventHandler();\n        }\n        return mInstance;\n    }\n\n    public void addHandler(Handler handler) {\n        if (!mEventHandler.contains(handler))\n            mEventHandler.add(handler);\n    }\n\n    public void removeHandler(Handler handler) {\n        mEventHandler.remove(handler);\n    }\n\n    /** This method is called by a native thread **/\n    public void callback(int event, Bundle b) {\n        b.putInt(\"event\", event);\n        for (int i = 0; i < mEventHandler.size(); i++) {\n            Message msg = Message.obtain();\n            msg.setData(b);\n            mEventHandler.get(i).sendMessage(msg);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/IVideoPlayer.java",
    "content": "/*****************************************************************************\n * IVideoPlayer.java\n *****************************************************************************\n * Copyright © 2010-2013 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\npublic interface IVideoPlayer {\n    /**\n     * This method is called by native vout to request a surface resize when frame size doesn't match surface size.\n     * @param width Frame width\n     * @param height Frame height\n     * @param visible_width Visible frame width\n     * @param visible_height Visible frame height\n     * @param sar_num Surface aspect ratio numerator\n     * @param sar_den Surface aspect ratio denominator\n     */\n    void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den);\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/LibVLC.java",
    "content": "/*****************************************************************************\n * LibVLC.java\n *****************************************************************************\n * Copyright © 2010-2013 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.util.Log;\nimport android.view.Surface;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Map;\n\npublic class LibVLC {\n    private static final String TAG = \"VLC/LibVLC\";\n    public static final int AOUT_AUDIOTRACK_JAVA = 0;\n    public static final int AOUT_AUDIOTRACK = 1;\n    public static final int AOUT_OPENSLES = 2;\n\n    public static final int VOUT_ANDROID_SURFACE = 0;\n    public static final int VOUT_OPEGLES2 = 1;\n\n    public static final int HW_ACCELERATION_AUTOMATIC = -1;\n    public static final int HW_ACCELERATION_DISABLED = 0;\n    public static final int HW_ACCELERATION_DECODING = 1;\n    public static final int HW_ACCELERATION_FULL = 2;\n\n    private static LibVLC sInstance;\n\n    /** libVLC instance C pointer */\n    private long mLibVlcInstance = 0; // Read-only, reserved for JNI\n    /** libvlc_media_player pointer and index */\n    private int mInternalMediaPlayerIndex = 0; // Read-only, reserved for JNI\n    private long mInternalMediaPlayerInstance = 0; // Read-only, reserved for JNI\n\n    private MediaList mMediaList; // Pointer to media list being followed\n    private MediaList mPrimaryList; // Primary/default media list; see getPrimaryMediaList()\n\n    /** Buffer for VLC messages */\n    private StringBuffer mDebugLogBuffer;\n    private boolean mIsBufferingLog = false;\n\n    private AudioOutput mAout;\n\n    /** Keep screen bright */\n    //private WakeLock mWakeLock;\n\n    /** Settings */\n    private int hardwareAcceleration = HW_ACCELERATION_AUTOMATIC;\n    private String subtitlesEncoding = \"\";\n    private int aout = LibVlcUtil.isGingerbreadOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA;\n    private int vout = VOUT_ANDROID_SURFACE;\n    private boolean timeStretching = false;\n    private int deblocking = -1;\n    private String chroma = \"\";\n    private boolean verboseMode = true;\n    private float[] equalizer = null;\n    private boolean frameSkip = false;\n    private int networkCaching = 0;\n\n    /** Path of application-specific cache */\n    private String mCachePath = \"\";\n\n    /** Native crash handler */\n    private OnNativeCrashListener mOnNativeCrashListener;\n\n    /** Check in libVLC already initialized otherwise crash */\n    private boolean mIsInitialized = false;\n    public native void attachSurface(Surface surface, IVideoPlayer player);\n\n    public native void detachSurface();\n\n    public native void attachSubtitlesSurface(Surface surface);\n    public native void detachSubtitlesSurface();\n\n    public native void eventVideoPlayerActivityCreated(boolean created);\n\n    /* Load library before object instantiation */\n    static {\n        try {\n            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)\n                System.loadLibrary(\"iomx-gingerbread\");\n            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)\n                System.loadLibrary(\"iomx-hc\");\n            else\n                System.loadLibrary(\"iomx-ics\");\n        } catch (Throwable t) {\n            // No need to warn if it isn't found, when we intentionally don't build these except for debug\n            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)\n                Log.w(TAG, \"Unable to load the iomx library: \" + t);\n        }\n        try {\n            System.loadLibrary(\"vlcjni\");\n        } catch (UnsatisfiedLinkError ule) {\n            Log.e(TAG, \"Can't load vlcjni library: \" + ule);\n            /// FIXME Alert user\n            System.exit(1);\n        } catch (SecurityException se) {\n            Log.e(TAG, \"Encountered a security issue when loading vlcjni library: \" + se);\n            /// FIXME Alert user\n            System.exit(1);\n        }\n    }\n\n    /**\n     * Singleton constructor of libVLC Without surface and vout to create the\n     * thumbnail and get information e.g. on the MediaLibraryActivity\n     *\n     * @return libVLC instance\n     * @throws org.videolan.libvlc.LibVlcException\n     */\n    public static LibVLC getInstance() throws LibVlcException {\n        synchronized (LibVLC.class) {\n            if (sInstance == null) {\n                /* First call */\n                sInstance = new LibVLC();\n            }\n        }\n\n        return sInstance;\n    }\n\n    /**\n     * Return an existing instance of libVLC Call it when it is NOT important\n     * that this fails\n     *\n     * @return libVLC instance OR null\n     */\n    public static LibVLC getExistingInstance() {\n        synchronized (LibVLC.class) {\n            return sInstance;\n        }\n    }\n\n    /**\n     * Constructor\n     * It is private because this class is a singleton.\n     */\n    private LibVLC() {\n        mAout = new AudioOutput();\n    }\n\n    /**\n     * Destructor:\n     * It is bad practice to rely on them, so please don't forget to call\n     * destroy() before exiting.\n     */\n    @Override\n    protected void finalize() {\n        if (mLibVlcInstance != 0) {\n            Log.d(TAG, \"LibVLC is was destroyed yet before finalize()\");\n            destroy();\n        }\n    }\n\n    /**\n     * Get the media list that LibVLC is following right now.\n     *\n     * @return The media list object being followed\n     */\n    public MediaList getMediaList() {\n        return mMediaList;\n    }\n\n    /**\n     * Set the media list for LibVLC to follow.\n     *\n     * @param mediaList The media list object to follow\n     */\n    public void setMediaList(MediaList mediaList) {\n        mMediaList = mediaList;\n    }\n\n    /**\n     * Sets LibVLC to follow the default media list (see below)\n     */\n    public void setMediaList() {\n        mMediaList = mPrimaryList;\n    }\n\n    /**\n     * Gets the primary media list, or the \"currently playing\" list.\n     * Not to be confused with the media list pointer from above, which\n     * refers the the MediaList object that libVLC is currently following.\n     * This list is just one out of many lists that it can be pointed towards.\n     *\n     * This list will be used for lists of songs that are not user-defined.\n     * For example: selecting a song from the Songs list, or from the list\n     * displayed after selecting an album.\n     *\n     * It is loaded as the default list.\n     *\n     * @return The primary media list\n     */\n    public MediaList getPrimaryMediaList() {\n        return mPrimaryList;\n    }\n\n    /**\n     * Give to LibVLC the surface to draw the video.\n     * @param f the surface to draw\n     */\n    public native void setSurface(Surface f);\n\n    public static synchronized void restart(Context context) {\n        if (sInstance != null) {\n            try {\n                sInstance.destroy();\n                sInstance.init(context);\n            } catch (LibVlcException lve) {\n                Log.e(TAG, \"Unable to reinit libvlc: \" + lve);\n            }\n        }\n    }\n\n    /**\n     * those get/is* are called from native code to get settings values.\n     */\n\n    public int getHardwareAcceleration() {\n        return this.hardwareAcceleration;\n    }\n\n    public void setHardwareAcceleration(int hardwareAcceleration) {\n        if (hardwareAcceleration < 0) {\n            // Automatic mode: activate MediaCodec opaque direct rendering for 4.3 and above.\n            if (LibVlcUtil.isJellyBeanMR2OrLater())\n                this.hardwareAcceleration = HW_ACCELERATION_FULL;\n            else\n                this.hardwareAcceleration = HW_ACCELERATION_DISABLED;\n        }\n        else\n            this.hardwareAcceleration = hardwareAcceleration;\n    }\n\n    public String getSubtitlesEncoding() {\n        return subtitlesEncoding;\n    }\n\n    public void setSubtitlesEncoding(String subtitlesEncoding) {\n        this.subtitlesEncoding = subtitlesEncoding;\n    }\n\n    public int getAout() {\n        return aout;\n    }\n\n    public void setAout(int aout) {\n        if (aout < 0)\n            this.aout = LibVlcUtil.isICSOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA;\n        else\n            this.aout = aout;\n    }\n\n    public int getVout() {\n        return vout;\n    }\n\n    public void setVout(int vout) {\n        if (vout < 0)\n            this.vout = VOUT_ANDROID_SURFACE;\n        else\n            this.vout = vout;\n    }\n\n    public boolean timeStretchingEnabled() {\n        return timeStretching;\n    }\n\n    public void setTimeStretching(boolean timeStretching) {\n        this.timeStretching = timeStretching;\n    }\n\n    public int getDeblocking() {\n        int ret = deblocking;\n        if(deblocking < 0) {\n            /**\n             * Set some reasonable deblocking defaults:\n             *\n             * Skip all (4) for armv6 and MIPS by default\n             * Skip non-ref (1) for all armv7 more than 1.2 Ghz and more than 2 cores\n             * Skip non-key (3) for all devices that don't meet anything above\n             */\n            LibVlcUtil.MachineSpecs m = LibVlcUtil.getMachineSpecs();\n            if( (m.hasArmV6 && !(m.hasArmV7)) || m.hasMips )\n                ret = 4;\n            else if(m.frequency >= 1200 && m.processors > 2)\n                ret = 1;\n            else if(m.bogoMIPS >= 1200 && m.processors > 2) {\n                ret = 1;\n                Log.d(TAG, \"Used bogoMIPS due to lack of frequency info\");\n            } else\n                ret = 3;\n        } else if(deblocking > 4) { // sanity check\n            ret = 3;\n        }\n        return ret;\n    }\n\n    public void setDeblocking(int deblocking) {\n        this.deblocking = deblocking;\n    }\n\n    public String getChroma() {\n        return chroma;\n    }\n\n    public void setChroma(String chroma) {\n        this.chroma = chroma.equals(\"YV12\") && !LibVlcUtil.isGingerbreadOrLater() ? \"\" : chroma;\n    }\n\n    public boolean isVerboseMode() {\n        return verboseMode;\n    }\n\n    public void setVerboseMode(boolean verboseMode) {\n        this.verboseMode = verboseMode;\n    }\n\n    public float[] getEqualizer()\n    {\n        return equalizer;\n    }\n\n    public void setEqualizer(float[] equalizer)\n    {\n        this.equalizer = equalizer;\n        applyEqualizer();\n    }\n\n    private void applyEqualizer()\n    {\n        setNativeEqualizer(mInternalMediaPlayerInstance, this.equalizer);\n    }\n    private native int setNativeEqualizer(long mediaPlayer, float[] bands);\n\n    public boolean frameSkipEnabled() {\n        return frameSkip;\n    }\n\n    public void setFrameSkip(boolean frameskip) {\n        this.frameSkip = frameskip;\n    }\n\n    public int getNetworkCaching() {\n        return this.networkCaching;\n    }\n\n    public void setNetworkCaching(int networkcaching) {\n        this.networkCaching = networkcaching;\n    }\n\n    /**\n     * Initialize the libVLC class.\n     *\n     * This function must be called before using any libVLC functions.\n     *\n     * @throws org.videolan.libvlc.LibVlcException\n     */\n    public void init(Context context) throws LibVlcException {\n        Log.v(TAG, \"Initializing LibVLC\");\n        mDebugLogBuffer = new StringBuffer();\n        if (!mIsInitialized) {\n            if(!LibVlcUtil.hasCompatibleCPU(context)) {\n                Log.e(TAG, LibVlcUtil.getErrorMsg());\n                throw new LibVlcException();\n            }\n\n            File cacheDir = context.getCacheDir();\n            mCachePath = (cacheDir != null) ? cacheDir.getAbsolutePath() : null;\n            nativeInit();\n            mMediaList = mPrimaryList = new MediaList(this);\n            setEventHandler(EventHandler.getInstance());\n            mIsInitialized = true;\n        }\n    }\n\n    /**\n     * Destroy this libVLC instance\n     * @note You must call it before exiting\n     */\n    public void destroy() {\n        Log.v(TAG, \"Destroying LibVLC instance\");\n        nativeDestroy();\n        detachEventHandler();\n        mIsInitialized = false;\n    }\n\n    /**\n     * Open the Java audio output.\n     * This function is called by the native code\n     */\n    public void initAout(int sampleRateInHz, int channels, int samples) {\n        Log.d(TAG, \"Opening the java audio output\");\n        mAout.init(sampleRateInHz, channels, samples);\n    }\n\n    /**\n     * Play an audio buffer taken from the native code\n     * This function is called by the native code\n     */\n    public void playAudio(byte[] audioData, int bufferSize) {\n        mAout.playBuffer(audioData, bufferSize);\n    }\n\n    /**\n     * Pause the Java audio output\n     * This function is called by the native code\n     */\n    public void pauseAout() {\n        Log.d(TAG, \"Pausing the java audio output\");\n        mAout.pause();\n    }\n\n    /**\n     * Close the Java audio output\n     * This function is called by the native code\n     */\n    public void closeAout() {\n        Log.d(TAG, \"Closing the java audio output\");\n        mAout.release();\n    }\n\n    /**\n     * Play a media from the media list (playlist)\n     *\n     * @param position The index of the media\n     */\n    public void playIndex(int position) {\n        String mrl = mMediaList.getMRL(position);\n        if (mrl == null)\n            return;\n        String[] options = mMediaList.getMediaOptions(position);\n        mInternalMediaPlayerIndex = position;\n        playMRL(mLibVlcInstance, mrl, options);\n    }\n\n    /**\n     * Play an MRL directly.\n     *\n     * @param mrl MRL of the media to play.\n     */\n    public void playMRL(String mrl) {\n        // index=-1 will return options from libvlc instance without relying on MediaList\n        String[] options = mMediaList.getMediaOptions(-1);\n        mInternalMediaPlayerIndex = 0;\n        playMRL(mLibVlcInstance, mrl, options);\n    }\n\n    public TrackInfo[] readTracksInfo(String mrl) {\n        return readTracksInfo(mLibVlcInstance, mrl);\n    }\n\n    /**\n     * Get a media thumbnail.\n     */\n    public byte[] getThumbnail(String mrl, int i_width, int i_height) {\n        return getThumbnail(mLibVlcInstance, mrl, i_width, i_height);\n    }\n\n    /**\n     * Return true if there is a video track in the file\n     */\n    public boolean hasVideoTrack(String mrl) throws java.io.IOException {\n        return hasVideoTrack(mLibVlcInstance, mrl);\n    }\n\n    /**\n     * Sets the speed of playback (1 being normal speed, 2 being twice as fast)\n     *\n     * @param rate\n     */\n    public native void setRate(float rate);\n\n    /**\n     * Get the current playback speed\n     */\n    public native float getRate();\n\n    /**\n     * Initialize the libvlc C library\n     * @return a pointer to the libvlc instance\n     */\n    private native void nativeInit() throws LibVlcException;\n\n    /**\n     * Close the libvlc C library\n     * @note mLibVlcInstance should be 0 after a call to destroy()\n     */\n    private native void nativeDestroy();\n\n    /**\n     * Start buffering to the mDebugLogBuffer.\n     */\n    public native void startDebugBuffer();\n    public native void stopDebugBuffer();\n    public String getBufferContent() {\n        return mDebugLogBuffer.toString();\n    }\n\n    public void clearBuffer() {\n        mDebugLogBuffer.setLength(0);\n    }\n\n    public boolean isDebugBuffering() {\n        return mIsBufferingLog;\n    }\n\n    /**\n     * Play an mrl\n     */\n    private native void playMRL(long instance, String mrl, String[] mediaOptions);\n\n    /**\n     * Returns true if any media is playing\n     */\n    public native boolean isPlaying();\n\n    /**\n     * Returns true if any media is seekable\n     */\n    public native boolean isSeekable();\n\n    /**\n     * Plays any loaded media\n     */\n    public native void play();\n\n    /**\n     * Pauses any playing media\n     */\n    public native void pause();\n\n    /**\n     * Stops any playing media\n     */\n    public native void stop();\n\n    /**\n     * Get player state.\n     */\n    public native int getPlayerState();\n\n    /**\n     * Gets volume as integer\n     */\n    public native int getVolume();\n\n    /**\n     * Sets volume as integer\n     * @param volume: Volume level passed as integer\n     */\n    public native int setVolume(int volume);\n\n    /**\n     * Gets the current movie time (in ms).\n     * @return the movie time (in ms), or -1 if there is no media.\n     */\n    public native long getTime();\n\n    /**\n     * Sets the movie time (in ms), if any media is being played.\n     * @param time: Time in ms.\n     * @return the movie time (in ms), or -1 if there is no media.\n     */\n    public native long setTime(long time);\n\n    /**\n     * Gets the movie position.\n     * @return the movie position, or -1 for any error.\n     */\n    public native float getPosition();\n\n    /**\n     * Sets the movie position.\n     * @param pos: movie position.\n     */\n    public native void setPosition(float pos);\n\n    /**\n     * Gets current movie's length in ms.\n     * @return the movie length (in ms), or -1 if there is no media.\n     */\n    public native long getLength();\n\n    /**\n     * Get the libVLC version\n     * @return the libVLC version string\n     */\n    public native String version();\n\n    /**\n     * Get the libVLC compiler\n     * @return the libVLC compiler string\n     */\n    public native String compiler();\n\n    /**\n     * Get the libVLC changeset\n     * @return the libVLC changeset string\n     */\n    public native String changeset();\n\n    /**\n     * Get a media thumbnail.\n     * @return a bytearray with the RGBA thumbnail data inside.\n     */\n    private native byte[] getThumbnail(long instance, String mrl, int i_width, int i_height);\n\n    /**\n     * Return true if there is a video track in the file\n     */\n    private native boolean hasVideoTrack(long instance, String mrl);\n\n    private native TrackInfo[] readTracksInfo(long instance, String mrl);\n\n    public native TrackInfo[] readTracksInfoInternal();\n\n    public native int getAudioTracksCount();\n\n    public native Map<Integer,String> getAudioTrackDescription();\n\n    public native Map<String, Object> getStats();\n\n    public native int getAudioTrack();\n\n    public native int setAudioTrack(int index);\n\n    public native int getVideoTracksCount();\n\n    public native int addSubtitleTrack(String path);\n\n    public native Map<Integer,String> getSpuTrackDescription();\n\n    public native int getSpuTrack();\n\n    public native int setSpuTrack(int index);\n\n    public native int getSpuTracksCount();\n\n    public static native String nativeToURI(String path);\n    \n    public native static void sendMouseEvent( int action, int button, int x, int y);\n\n    /**\n     * Quickly converts path to URIs, which are mandatory in libVLC.\n     *\n     * @param path\n     *            The path to be converted.\n     * @return A URI representation of path\n     */\n    public static String PathToURI(String path) {\n        if(path == null) {\n            throw new NullPointerException(\"Cannot convert null path!\");\n        }\n        return LibVLC.nativeToURI(path);\n    }\n\n    public static native void nativeReadDirectory(String path, ArrayList<String> res);\n\n    public native static boolean nativeIsPathDirectory(String path);\n\n     /**\n      * Expand and continue playing the current media.\n      *\n      * @return the index of the media was expanded, and -1 if no media was expanded\n      */\n    public int expandAndPlay() {\n        int r = mMediaList.expandMedia(mInternalMediaPlayerIndex);\n        if(r == 0)\n            this.playIndex(mInternalMediaPlayerIndex);\n        return r;\n    }\n\n    /**\n     * Expand the current media.\n     * @return the index of the media was expanded, and -1 if no media was expanded\n     */\n    public int expand() {\n        return mMediaList.expandMedia(mInternalMediaPlayerIndex);\n    }\n\n    private native void setEventHandler(EventHandler eventHandler);\n\n    private native void detachEventHandler();\n\n    public native float[] getBands();\n\n    public native String[] getPresets();\n\n    public native float[] getPreset(int index);\n\n    public static interface OnNativeCrashListener {\n        public void onNativeCrash();\n    }\n\n    public void setOnNativeCrashListener(OnNativeCrashListener l) {\n        mOnNativeCrashListener = l;\n    }\n\n    private void onNativeCrash() {\n        if (mOnNativeCrashListener != null)\n            mOnNativeCrashListener.onNativeCrash();\n    }\n\n    public String getCachePath() {\n        return mCachePath;\n    }\n\n    public native int getTitle();\n    public native void setTitle(int title);\n    public native int getChapterCountForTitle(int title);\n    public native int getTitleCount();\n\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/LibVlcException.java",
    "content": "/*****************************************************************************\n * LibVlcException.java\n *****************************************************************************\n * Copyright © 2011-2012 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\n/**\n * LibVlcException: exceptions thrown by the native LibVLC interface\n */\npackage org.videolan.libvlc;\n\n/**\n * @author jpeg\n *\n */\npublic class LibVlcException extends Exception {\n    private static final long serialVersionUID = -1909522348226924189L;\n\n    /**\n     * Create an empty error\n     */\n    public LibVlcException() {\n        super();\n    }\n\n    /**\n     * @param detailMessage\n     */\n    public LibVlcException(String detailMessage) {\n        super(detailMessage);\n    }\n\n    /**\n     * @param throwable\n     */\n    public LibVlcException(Throwable throwable) {\n        super(throwable);\n    }\n\n    /**\n     * @param detailMessage\n     * @param throwable\n     */\n    public LibVlcException(String detailMessage, Throwable throwable) {\n        super(detailMessage, throwable);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/LibVlcUtil.java",
    "content": "/*****************************************************************************\n * LibVlcUtil.java\n *****************************************************************************\n * Copyright © 2011-2013 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Locale;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.util.Log;\n\npublic class LibVlcUtil {\n    public final static String TAG = \"VLC/LibVLC/Util\";\n\n    public static boolean isFroyoOrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;\n    }\n\n    public static boolean isGingerbreadOrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;\n    }\n\n    public static boolean isHoneycombOrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;\n    }\n\n    public static boolean isICSOrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;\n    }\n\n    public static boolean isJellyBeanOrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;\n    }\n\n    public static boolean isJellyBeanMR1OrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;\n    }\n\n    public static boolean isJellyBeanMR2OrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;\n    }\n\n    public static boolean isKitKatOrLater()\n    {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;\n    }\n\n    private static String errorMsg = null;\n    private static boolean isCompatible = false;\n    public static String getErrorMsg() {\n        return errorMsg;\n    }\n\n    public static File URItoFile(String URI) {\n        if(URI == null) return null;\n        return new File(Uri.decode(URI).replace(\"file://\",\"\"));\n    }\n\n    public static String URItoFileName(String URI) {\n        if(URI == null) return null;\n        return URItoFile(URI).getName();\n    }\n\n    public static boolean hasCompatibleCPU(Context context)\n    {\n        // If already checked return cached result\n        if(errorMsg != null || isCompatible) return isCompatible;\n\n        ElfData elf = readLib(context.getApplicationInfo().dataDir + \"/lib/libvlcjni.so\");\n        if(elf == null) {\n            Log.e(TAG, \"WARNING: Unable to read libvlcjni.so; cannot check device ABI!\");\n            Log.e(TAG, \"WARNING: Cannot guarantee correct ABI for this build (may crash)!\");\n            return true;\n        }\n\n        String CPU_ABI = Build.CPU_ABI;\n        String CPU_ABI2 = \"none\";\n        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { // CPU_ABI2 since 2.2\n            try {\n                CPU_ABI2 = (String)Build.class.getDeclaredField(\"CPU_ABI2\").get(null);\n            } catch (Exception e) { }\n        }\n\n        Log.i(TAG, \"machine = \" + (elf.e_machine == EM_ARM ? \"arm\" : elf.e_machine == EM_386 ? \"x86\" : \"mips\"));\n        Log.i(TAG, \"arch = \" + elf.att_arch);\n        Log.i(TAG, \"fpu = \" + elf.att_fpu);\n        boolean hasNeon = false, hasFpu = false, hasArmV6 = false,\n                hasArmV7 = false, hasMips = false, hasX86 = false;\n        float bogoMIPS = -1;\n        int processors = 0;\n\n        if(CPU_ABI.equals(\"x86\") ||\n           CPU_ABI2.equals(\"x86\")) {\n            hasX86 = true;\n        } else if(CPU_ABI.equals(\"armeabi-v7a\") ||\n                  CPU_ABI2.equals(\"armeabi-v7a\")) {\n            hasArmV7 = true;\n            hasArmV6 = true; /* Armv7 is backwards compatible to < v6 */\n        } else if(CPU_ABI.equals(\"armeabi\") ||\n                  CPU_ABI2.equals(\"armeabi\")) {\n            hasArmV6 = true;\n        }\n\n        try {\n            FileReader fileReader = new FileReader(\"/proc/cpuinfo\");\n            BufferedReader br = new BufferedReader(fileReader);\n            String line;\n            while((line = br.readLine()) != null) {\n                if(!hasArmV7 && line.contains(\"ARMv7\")) {\n                    hasArmV7 = true;\n                    hasArmV6 = true; /* Armv7 is backwards compatible to < v6 */\n                }\n                if(!hasArmV7 && !hasArmV6 && line.contains(\"ARMv6\"))\n                    hasArmV6 = true;\n                // \"clflush size\" is a x86-specific cpuinfo tag.\n                // (see kernel sources arch/x86/kernel/cpu/proc.c)\n                if(line.contains(\"clflush size\"))\n                    hasX86 = true;\n                if(line.contains(\"GenuineIntel\"))\n                    hasX86 = true;\n                // \"microsecond timers\" is specific to MIPS.\n                // see arch/mips/kernel/proc.c\n                if(line.contains(\"microsecond timers\"))\n                    hasMips = true;\n                if(!hasNeon && line.contains(\"neon\"))\n                    hasNeon = true;\n                if(!hasFpu && line.contains(\"vfp\"))\n                    hasFpu = true;\n                if(line.startsWith(\"processor\"))\n                    processors++;\n                if(bogoMIPS < 0 && line.toLowerCase(Locale.ENGLISH).contains(\"bogomips\")) {\n                    String[] bogo_parts = line.split(\":\");\n                    try {\n                        bogoMIPS = Float.parseFloat(bogo_parts[1].trim());\n                    } catch(NumberFormatException e) {\n                        bogoMIPS = -1; // invalid bogomips\n                    }\n                }\n            }\n            fileReader.close();\n        } catch(IOException ex){\n            ex.printStackTrace();\n            errorMsg = \"IOException whilst reading cpuinfo flags\";\n            isCompatible = false;\n            return false;\n        }\n        if(processors == 0)\n            processors = 1; // possibly borked cpuinfo?\n\n        // Enforce proper architecture to prevent problems\n        if(elf.e_machine == EM_386 && !hasX86) {\n            errorMsg = \"x86 build on non-x86 device\";\n            isCompatible = false;\n            return false;\n        } else if(elf.e_machine == EM_ARM && hasX86) {\n            errorMsg = \"ARM build on x86 device\";\n            isCompatible = false;\n            return false;\n        }\n\n        if(elf.e_machine == EM_MIPS && !hasMips) {\n            errorMsg = \"MIPS build on non-MIPS device\";\n            isCompatible = false;\n            return false;\n        } else if(elf.e_machine == EM_ARM && hasMips) {\n            errorMsg = \"ARM build on MIPS device\";\n            isCompatible = false;\n            return false;\n        }\n\n        if(elf.e_machine == EM_ARM && elf.att_arch.startsWith(\"v7\") && !hasArmV7) {\n            errorMsg = \"ARMv7 build on non-ARMv7 device\";\n            isCompatible = false;\n            return false;\n        }\n        if(elf.e_machine == EM_ARM) {\n            if(elf.att_arch.startsWith(\"v6\") && !hasArmV6) {\n                errorMsg = \"ARMv6 build on non-ARMv6 device\";\n                isCompatible = false;\n                return false;\n            } else if(elf.att_fpu && !hasFpu) {\n                errorMsg = \"FPU-enabled build on non-FPU device\";\n                isCompatible = false;\n                return false;\n            }\n        }\n\n        float frequency = -1;\n        try {\n            FileReader fileReader = new FileReader(\"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq\");\n            BufferedReader br = new BufferedReader(fileReader);\n            String line = \"\";\n            try {\n                line = br.readLine();\n                frequency = Float.parseFloat(line) / 1000.f; /* Convert to MHz */\n            } catch(NumberFormatException e) {\n                Log.w(TAG, \"Could not parse maximum CPU frequency!\");\n                Log.w(TAG, \"Failed to parse: \" + line);\n            }\n            fileReader.close();\n        } catch(IOException ex) {\n            Log.w(TAG, \"Could not find maximum CPU frequency!\");\n        }\n\n        errorMsg = null;\n        isCompatible = true;\n        // Store into MachineSpecs\n        machineSpecs = new MachineSpecs();\n        machineSpecs.hasArmV6 = hasArmV6;\n        machineSpecs.hasArmV7 = hasArmV7;\n        machineSpecs.hasFpu = hasFpu;\n        machineSpecs.hasMips = hasMips;\n        machineSpecs.hasNeon = hasNeon;\n        machineSpecs.hasX86 = hasX86;\n        machineSpecs.bogoMIPS = bogoMIPS;\n        machineSpecs.processors = processors;\n        machineSpecs.frequency = frequency;\n        return true;\n    }\n\n    public static MachineSpecs getMachineSpecs() {\n        return machineSpecs;\n    }\n    private static MachineSpecs machineSpecs = null;\n    public static class MachineSpecs {\n        public boolean hasNeon;\n        public boolean hasFpu;\n        public boolean hasArmV6;\n        public boolean hasArmV7;\n        public boolean hasMips;\n        public boolean hasX86;\n        public float bogoMIPS;\n        public int processors;\n        public float frequency; /* in MHz */\n    }\n\n    private static final int EM_386 = 3;\n    private static final int EM_MIPS = 8;\n    private static final int EM_ARM = 40;\n    private static final int ELF_HEADER_SIZE = 52;\n    private static final int SECTION_HEADER_SIZE = 40;\n    private static final int SHT_ARM_ATTRIBUTES = 0x70000003;\n    private static class ElfData {\n        ByteOrder order;\n        int e_machine;\n        int e_shoff;\n        int e_shnum;\n        int sh_offset;\n        int sh_size;\n        String att_arch;\n        boolean att_fpu;\n    }\n\n    /** '*' prefix means it's unsupported */\n    private static String[] CPU_archs = {\"*Pre-v4\", \"*v4\", \"*v4T\",\n                                         \"v5T\", \"v5TE\", \"v5TEJ\",\n                                         \"v6\", \"v6KZ\", \"v6T2\", \"v6K\", \"v7\",\n                                         \"*v6-M\", \"*v6S-M\", \"*v7E-M\", \"*v8\"};\n\n    private static ElfData readLib(String path) {\n        File file = new File(path);\n        if (!file.exists() || !file.canRead())\n            return null;\n\n        RandomAccessFile in = null;\n        try {\n            in = new RandomAccessFile(file, \"r\");\n\n            ElfData elf = new ElfData();\n            if (!readHeader(in, elf))\n                return null;\n\n            switch (elf.e_machine) {\n                case EM_386:\n                case EM_MIPS:\n                    return elf;\n                case EM_ARM:\n                    in.close();\n                    in = new RandomAccessFile(file, \"r\");\n                    if (!readSection(in, elf))\n                        return null;\n                    in.close();\n                    in = new RandomAccessFile(file, \"r\");\n                    if (!readArmAttributes(in, elf))\n                        return null;\n                    break;\n                default:\n                    return null;\n            }\n            return elf;\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (in != null)\n                    in.close();\n            } catch (IOException e) {\n            }\n        }\n        return null;\n    }\n\n    private static boolean readHeader(RandomAccessFile in, ElfData elf) throws IOException {\n        // http://www.sco.com/developers/gabi/1998-04-29/ch4.eheader.html\n        byte[] bytes = new byte[ELF_HEADER_SIZE];\n        in.readFully(bytes);\n        if (bytes[0] != 127 ||\n                bytes[1] != 'E' ||\n                bytes[2] != 'L' ||\n                bytes[3] != 'F' ||\n                bytes[4] != 1) { // ELFCLASS32, Only 32bit header is supported\n            return false;\n        }\n\n        elf.order = bytes[5] == 1\n                ? ByteOrder.LITTLE_ENDIAN // ELFDATA2LSB\n                : ByteOrder.BIG_ENDIAN;   // ELFDATA2MSB\n\n        // wrap bytes in a ByteBuffer to force endianess\n        ByteBuffer buffer = ByteBuffer.wrap(bytes);\n        buffer.order(elf.order);\n\n        elf.e_machine = buffer.getShort(18);    /* Architecture */\n        elf.e_shoff = buffer.getInt(32);        /* Section header table file offset */\n        elf.e_shnum = buffer.getShort(48);      /* Section header table entry count */\n        return true;\n    }\n\n    private static boolean readSection(RandomAccessFile in, ElfData elf) throws IOException {\n        byte[] bytes = new byte[SECTION_HEADER_SIZE];\n        in.seek(elf.e_shoff);\n\n        for (int i = 0; i < elf.e_shnum; ++i) {\n            in.readFully(bytes);\n\n            // wrap bytes in a ByteBuffer to force endianess\n            ByteBuffer buffer = ByteBuffer.wrap(bytes);\n            buffer.order(elf.order);\n\n            int sh_type = buffer.getInt(4); /* Section type */\n            if (sh_type != SHT_ARM_ATTRIBUTES)\n                continue;\n\n            elf.sh_offset = buffer.getInt(16);  /* Section file offset */\n            elf.sh_size = buffer.getInt(20);    /* Section size in bytes */\n            return true;\n        }\n\n        return false;\n    }\n\n    private static boolean readArmAttributes(RandomAccessFile in, ElfData elf) throws IOException {\n        byte[] bytes = new byte[elf.sh_size];\n        in.seek(elf.sh_offset);\n        in.readFully(bytes);\n\n        // wrap bytes in a ByteBuffer to force endianess\n        ByteBuffer buffer = ByteBuffer.wrap(bytes);\n        buffer.order(elf.order);\n\n        //http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf\n        //http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf\n        if (buffer.get() != 'A') // format-version\n            return false;\n\n        // sub-sections loop\n        while (buffer.remaining() > 0) {\n            int start_section = buffer.position();\n            int length = buffer.getInt();\n            String vendor = getString(buffer);\n            if (vendor.equals(\"aeabi\")) {\n                // tags loop\n                while (buffer.position() < start_section + length) {\n                    int start = buffer.position();\n                    int tag = buffer.get();\n                    int size = buffer.getInt();\n                    // skip if not Tag_File, we don't care about others\n                    if (tag != 1) {\n                        buffer.position(start + size);\n                        continue;\n                    }\n\n                    // attributes loop\n                    while (buffer.position() < start + size) {\n                        tag = getUleb128(buffer);\n                        if (tag == 6) { // CPU_arch\n                            int arch = getUleb128(buffer);\n                            elf.att_arch = CPU_archs[arch];\n                        }\n                        else if (tag == 27) { // ABI_HardFP_use\n                            getUleb128(buffer);\n                            elf.att_fpu = true;\n                        }\n                        else {\n                            // string for 4=CPU_raw_name / 5=CPU_name / 32=compatibility\n                            // string for >32 && odd tags\n                            // uleb128 for other\n                            tag %= 128;\n                            if (tag == 4 || tag == 5 || tag == 32 || (tag > 32 && (tag & 1) != 0))\n                                getString(buffer);\n                            else\n                                getUleb128(buffer);\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        return true;\n    }\n\n    private static String getString(ByteBuffer buffer) {\n        StringBuilder sb = new StringBuilder(buffer.limit());\n        while (buffer.remaining() > 0) {\n            char c = (char) buffer.get();\n            if (c == 0)\n                break;\n            sb.append(c);\n        }\n        return sb.toString();\n    }\n\n    private static int getUleb128(ByteBuffer buffer) {\n        int ret = 0;\n        int c;\n        do {\n            ret <<= 7;\n            c = buffer.get();\n            ret |= c & 0x7f;\n        } while((c & 0x80) > 0);\n\n        return ret;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/Media.java",
    "content": "/*****************************************************************************\n * Media.java\n *****************************************************************************\n * Copyright © 2011-2013 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.HashSet;\nimport java.util.Locale;\n\nimport android.graphics.Bitmap;\nimport android.util.Log;\n\npublic class Media implements Comparable<Media> {\n    public final static String TAG = \"VLC/LibVLC/Media\";\n\n    public final static HashSet<String> VIDEO_EXTENSIONS;\n    public final static HashSet<String> AUDIO_EXTENSIONS;\n    public final static String EXTENSIONS_REGEX;\n    public final static HashSet<String> FOLDER_BLACKLIST;\n\n    static {\n        String[] video_extensions = {\n                \".3g2\", \".3gp\", \".3gp2\", \".3gpp\", \".amv\", \".asf\", \".avi\", \".divx\", \".drc\", \".dv\",\n                \".f4v\", \".flv\", \".gvi\", \".gxf\", \".ismv\", \".iso\", \".m1v\", \".m2v\", \".m2t\", \".m2ts\",\n                \".m4v\", \".mkv\", \".mov\", \".mp2\", \".mp2v\", \".mp4\", \".mp4v\", \".mpe\", \".mpeg\",\n                \".mpeg1\", \".mpeg2\", \".mpeg4\", \".mpg\", \".mpv2\", \".mts\", \".mtv\", \".mxf\", \".mxg\",\n                \".nsv\", \".nut\", \".nuv\", \".ogm\", \".ogv\", \".ogx\", \".ps\", \".rec\", \".rm\", \".rmvb\",\n                \".tod\", \".ts\", \".tts\", \".vob\", \".vro\", \".webm\", \".wm\", \".wmv\", \".wtv\", \".xesc\" };\n\n        String[] audio_extensions = {\n                \".3ga\", \".a52\", \".aac\", \".ac3\", \".adt\", \".adts\", \".aif\", \".aifc\", \".aiff\", \".amr\",\n                \".aob\", \".ape\", \".awb\", \".caf\", \".dts\", \".flac\", \".it\", \".m4a\", \".m4b\", \".m4p\",\n                \".mid\", \".mka\", \".mlp\", \".mod\", \".mpa\", \".mp1\", \".mp2\", \".mp3\", \".mpc\", \".mpga\",\n                \".oga\", \".ogg\", \".oma\", \".opus\", \".ra\", \".ram\", \".rmi\", \".s3m\", \".spx\", \".tta\",\n                \".voc\", \".vqf\", \".w64\", \".wav\", \".wma\", \".wv\", \".xa\", \".xm\" };\n\n        String[] folder_blacklist = {\n                \"/alarms\",\n                \"/notifications\",\n                \"/ringtones\",\n                \"/media/alarms\",\n                \"/media/notifications\",\n                \"/media/ringtones\",\n                \"/media/audio/alarms\",\n                \"/media/audio/notifications\",\n                \"/media/audio/ringtones\",\n                \"/Android/data/\" };\n\n        VIDEO_EXTENSIONS = new HashSet<String>();\n        for (String item : video_extensions)\n            VIDEO_EXTENSIONS.add(item);\n        AUDIO_EXTENSIONS = new HashSet<String>();\n        for (String item : audio_extensions)\n            AUDIO_EXTENSIONS.add(item);\n\n        StringBuilder sb = new StringBuilder(115);\n        sb.append(\".+(\\\\.)((?i)(\");\n        sb.append(video_extensions[0].substring(1));\n        for(int i = 1; i < video_extensions.length; i++) {\n            sb.append('|');\n            sb.append(video_extensions[i].substring(1));\n        }\n        for(int i = 0; i < audio_extensions.length; i++) {\n            sb.append('|');\n            sb.append(audio_extensions[i].substring(1));\n        }\n        sb.append(\"))\");\n        EXTENSIONS_REGEX = sb.toString();\n        FOLDER_BLACKLIST = new HashSet<String>();\n        for (String item : folder_blacklist)\n            FOLDER_BLACKLIST.add(android.os.Environment.getExternalStorageDirectory().getPath() + item);\n    }\n\n    public final static int TYPE_ALL = -1;\n    public final static int TYPE_VIDEO = 0;\n    public final static int TYPE_AUDIO = 1;\n    public final static int TYPE_GROUP = 2;\n\n    /** Metadata from libvlc_media */\n    protected String mTitle;\n    private String mArtist;\n    private String mGenre;\n    private String mCopyright;\n    private String mAlbum;\n    private String mTrackNumber;\n    private String mDescription;\n    private String mRating;\n    private String mDate;\n    private String mSettings;\n    private String mNowPlaying;\n    private String mPublisher;\n    private String mEncodedBy;\n    private String mTrackID;\n    private String mArtworkURL;\n\n    private final String mLocation;\n    private String mFilename;\n    private long mTime = 0;\n    private int mAudioTrack = -1;\n    private int mSpuTrack = -2;\n    private long mLength = 0;\n    private int mType;\n    private int mWidth = 0;\n    private int mHeight = 0;\n    private Bitmap mPicture;\n    private boolean mIsPictureParsed;\n\n    /**\n     * Create a new Media\n     * @param libVLC A pointer to the libVLC instance. Should not be NULL\n     * @param URI The URI of the media.\n     */\n    public Media(LibVLC libVLC, String URI) {\n        if(libVLC == null)\n            throw new NullPointerException(\"libVLC was null\");\n\n        mLocation = URI;\n\n        mType = TYPE_ALL;\n        TrackInfo[] tracks = libVLC.readTracksInfo(mLocation);\n\n        extractTrackInfo(tracks);\n    }\n\n    private void extractTrackInfo(TrackInfo[] tracks) {\n        if (tracks == null)\n            return;\n\n        for (TrackInfo track : tracks) {\n            if (track.Type == TrackInfo.TYPE_VIDEO) {\n                mType = TYPE_VIDEO;\n                mWidth = track.Width;\n                mHeight = track.Height;\n            } else if (mType == TYPE_ALL && track.Type == TrackInfo.TYPE_AUDIO){\n                mType = TYPE_AUDIO;\n            } else if (track.Type == TrackInfo.TYPE_META) {\n                mLength = track.Length;\n                mTitle = track.Title;\n                mArtist = getValueWrapper(track.Artist, UnknownStringType.Artist);\n                mAlbum = getValueWrapper(track.Album, UnknownStringType.Album);\n                mGenre = getValueWrapper(track.Genre, UnknownStringType.Genre);\n                mArtworkURL = track.ArtworkURL;\n                Log.d(TAG, \"Title \" + mTitle);\n                Log.d(TAG, \"Artist \" + mArtist);\n                Log.d(TAG, \"Genre \" + mGenre);\n                Log.d(TAG, \"Album \" + mAlbum);\n            }\n        }\n\n        /* No useful ES found */\n        if (mType == TYPE_ALL) {\n            int dotIndex = mLocation.lastIndexOf(\".\");\n            if (dotIndex != -1) {\n                String fileExt = mLocation.substring(dotIndex).toLowerCase(Locale.ENGLISH);\n                if( Media.VIDEO_EXTENSIONS.contains(fileExt) ) {\n                    mType = TYPE_VIDEO;\n                } else if (Media.AUDIO_EXTENSIONS.contains(fileExt)) {\n                    mType = TYPE_AUDIO;\n                }\n            }\n        }\n    }\n\n    public Media(String location, long time, long length, int type,\n            Bitmap picture, String title, String artist, String genre, String album,\n            int width, int height, String artworkURL, int audio, int spu) {\n        mLocation = location;\n        mFilename = null;\n        mTime = time;\n        mAudioTrack = audio;\n        mSpuTrack = spu;\n        mLength = length;\n        mType = type;\n        mPicture = picture;\n        mWidth = width;\n        mHeight = height;\n\n        mTitle = title;\n        mArtist = getValueWrapper(artist, UnknownStringType.Artist);\n        mGenre = getValueWrapper(genre, UnknownStringType.Genre);\n        mAlbum = getValueWrapper(album, UnknownStringType.Album);\n        mArtworkURL = artworkURL;\n    }\n\n    private enum UnknownStringType { Artist , Genre, Album };\n    /**\n     * Uses introspection to read VLC l10n databases, so that we can sever the\n     * hard-coded dependency gracefully for 3rd party libvlc apps while still\n     * maintaining good l10n in VLC for Android.\n     *\n     * @see org.videolan.vlc.util.Util#getValue(String, int)\n     *\n     * @param string The default string\n     * @param type Alias for R.string.xxx\n     * @return The default string if not empty or string from introspection\n     */\n    private static String getValueWrapper(String string, UnknownStringType type) {\n        if(string != null && string.length() > 0) return string;\n\n        try {\n            Class<?> stringClass = Class.forName(\"org.videolan.vlc.R$string\");\n            Class<?> utilClass = Class.forName(\"org.videolan.vlc.Util\");\n\n            Integer value;\n            switch(type) {\n            case Album:\n                value = (Integer)stringClass.getField(\"unknown_album\").get(null);\n                break;\n            case Genre:\n                value = (Integer)stringClass.getField(\"unknown_genre\").get(null);\n                break;\n            case Artist:\n            default:\n                value = (Integer)stringClass.getField(\"unknown_artist\").get(null);\n                break;\n            }\n\n            Method getValueMethod = utilClass.getDeclaredMethod(\"getValue\", String.class, Integer.TYPE);\n            // Util.getValue(string, R.string.xxx);\n            return (String) getValueMethod.invoke(null, string, value);\n        } catch (ClassNotFoundException e) {\n        } catch (IllegalArgumentException e) {\n        } catch (IllegalAccessException e) {\n        } catch (NoSuchFieldException e) {\n        } catch (NoSuchMethodException e) {\n        } catch (InvocationTargetException e) {\n        }\n\n        // VLC for Android translations not available (custom app perhaps)\n        // Use hardcoded English phrases.\n        switch(type) {\n        case Album:\n            return \"Unknown Album\";\n        case Genre:\n            return \"Unknown Genre\";\n        case Artist:\n        default:\n            return \"Unknown Artist\";\n        }\n    }\n\n    /**\n     * Compare the filenames to sort items\n     */\n    @Override\n    public int compareTo(Media another) {\n        return mTitle.toUpperCase(Locale.getDefault()).compareTo(\n                another.getTitle().toUpperCase(Locale.getDefault()));\n    }\n\n    public String getLocation() {\n        return mLocation;\n    }\n\n    public void updateMeta() {\n\n    }\n\n    public String getFileName() {\n        if (mFilename == null) {\n            mFilename = LibVlcUtil.URItoFileName(mLocation);\n        }\n        return mFilename;\n    }\n\n    public long getTime() {\n        return mTime;\n    }\n\n    public void setTime(long time) {\n        mTime = time;\n    }\n\n    public int getAudioTrack() {\n        return mAudioTrack;\n    }\n\n    public void setAudioTrack(int track) {\n        mAudioTrack = track;\n    }\n\n    public int getSpuTrack() {\n        return mSpuTrack;\n    }\n\n    public void setSpuTrack(int track) {\n        mSpuTrack = track;\n    }\n\n    public long getLength() {\n        return mLength;\n    }\n\n    public int getType() {\n        return mType;\n    }\n\n    public int getWidth() {\n        return mWidth;\n    }\n\n    public int getHeight() {\n        return mHeight;\n    }\n\n    /**\n     * Returns the raw picture object. Likely to be NULL in VLC for Android\n     * due to lazy-loading.\n     *\n     * Use {@link org.videolan.vlc.util.Bitmap#getPictureFromCache(org.videolan.libvlc.Media)} instead.\n     *\n     * @return The raw picture or NULL\n     */\n    public Bitmap getPicture() {\n        return mPicture;\n    }\n\n    /**\n     * Sets the raw picture object.\n     *\n     * In VLC for Android, use {@link org.videolan.vlc.MediaDatabase#setPicture(org.videolan.libvlc.Media, android.graphics.Bitmap)} instead.\n     *\n     * @param p\n     */\n    public void setPicture(Bitmap p) {\n        mPicture = p;\n    }\n\n    public boolean isPictureParsed() {\n        return mIsPictureParsed;\n    }\n\n    public void setPictureParsed(boolean isParsed) {\n        mIsPictureParsed = isParsed;\n    }\n\n    public String getTitle() {\n        if (mTitle != null && mType != TYPE_VIDEO)\n            return mTitle;\n        else {\n            String fileName = getFileName();\n            if (fileName == null)\n                return \"\";\n            int end = fileName.lastIndexOf(\".\");\n            if (end <= 0)\n                return fileName;\n            return fileName.substring(0, end);\n        }\n    }\n\n    public String getSubtitle() {\n        return mType != TYPE_VIDEO ? mArtist + \" - \" + mAlbum : \"\";\n    }\n\n    public String getArtist() {\n        return mArtist;\n    }\n\n    public String getGenre() {\n        if(getValueWrapper(null, UnknownStringType.Genre).equals(mGenre))\n            return mGenre;\n        else if( mGenre.length() > 1)/* Make genres case insensitive via normalisation */\n            return Character.toUpperCase(mGenre.charAt(0)) + mGenre.substring(1).toLowerCase(Locale.getDefault());\n        else\n            return mGenre;\n    }\n\n    public String getCopyright() {\n        return mCopyright;\n    }\n\n    public String getAlbum() {\n        return mAlbum;\n    }\n\n    public String getTrackNumber() {\n        return mTrackNumber;\n    }\n\n    public String getDescription() {\n        return mDescription;\n    }\n\n    public String getRating() {\n        return mRating;\n    }\n\n    public String getDate() {\n        return mDate;\n    }\n\n    public String getSettings() {\n        return mSettings;\n    }\n\n    public String getNowPlaying() {\n        return mNowPlaying;\n    }\n\n    public String getPublisher() {\n        return mPublisher;\n    }\n\n    public String getEncodedBy() {\n        return mEncodedBy;\n    }\n\n    public String getTrackID() {\n        return mTrackID;\n    }\n\n    public String getArtworkURL() {\n        return mArtworkURL;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/MediaList.java",
    "content": "/*****************************************************************************\n * MediaList.java\n *****************************************************************************\n * Copyright © 2013 VLC authors and VideoLAN\n * Copyright © 2013 Edward Wang\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\npackage org.videolan.libvlc;\n\nimport java.util.ArrayList;\n\nimport android.os.Bundle;\n\n/**\n * Java/JNI wrapper for the libvlc_media_list_t structure.\n */\npublic class MediaList {\n    private static final String TAG = \"VLC/LibVLC/MediaList\";\n\n    /* Since the libvlc_media_t is not created until the media plays, we have\n     * to cache them here. */\n    private static class MediaHolder {\n        Media m;\n        boolean noVideo; // default false\n        boolean noHardwareAcceleration; // default false\n\n        public MediaHolder(Media media) {\n            m = media; noVideo = false; noHardwareAcceleration = false;\n        }\n        public MediaHolder(Media m_, boolean noVideo_, boolean noHardwareAcceleration_) {\n            m = m_; noVideo = noVideo_; noHardwareAcceleration = noHardwareAcceleration_;\n        }\n    }\n\n    /* TODO: add locking */\n    private ArrayList<MediaHolder> mInternalList;\n    private LibVLC mLibVLC; // Used to create new objects that require a libvlc instance\n    private EventHandler mEventHandler;\n\n    public MediaList(LibVLC libVLC) {\n        mEventHandler = new EventHandler(); // used in init() below to fire events at the correct targets\n        mInternalList = new ArrayList<MediaHolder>();\n        mLibVLC = libVLC;\n    }\n\n    /**\n     * Adds a media URI to the media list.\n     *\n     * @param mrl\n     *            The MRL to add. Must be a location and not a path.\n     *            {@link LibVLC#PathToURI(String)} can be used to convert a path\n     *            to a MRL.\n     */\n    public void add(String mrl) {\n        add(new Media(mLibVLC, mrl));\n    }\n    public void add(Media media) {\n        add(media, false, false);\n    }\n    public void add(Media media, boolean noVideo) {\n        add(media, noVideo, false);\n    }\n    public void add(Media media, boolean noVideo, boolean noHardwareAcceleration) {\n        mInternalList.add(new MediaHolder(media, noVideo, noHardwareAcceleration));\n        signal_list_event(EventHandler.CustomMediaListItemAdded, mInternalList.size() - 1, media.getLocation());\n    }\n\n    /**\n     * Clear the media list. (remove all media)\n     */\n    public void clear() {\n        // Signal to observers of media being deleted.\n        for(int i = 0; i < mInternalList.size(); i++) {\n            signal_list_event(EventHandler.CustomMediaListItemDeleted, i, mInternalList.get(i).m.getLocation());\n        }\n        mInternalList.clear();\n    }\n\n    private boolean isValid(int position) {\n        return position >= 0 && position < mInternalList.size();\n    }\n\n    /**\n     * This function checks the currently playing media for subitems at the given\n     * position, and if any exist, it will expand them at the same position\n     * and replace the current media.\n     *\n     * @param position The position to expand\n     * @return -1 if no subitems were found, 0 if subitems were expanded\n     */\n    public int expandMedia(int position) {\n        ArrayList<String> children = new ArrayList<String>();\n        int ret = expandMedia(mLibVLC, position, children);\n        if(ret == 0) {\n            mEventHandler.callback(EventHandler.CustomMediaListExpanding, new Bundle());\n            this.remove(position);\n            for(String mrl : children) {\n                this.insert(position, mrl);\n            }\n            mEventHandler.callback(EventHandler.CustomMediaListExpandingEnd, new Bundle());\n        }\n        return ret;\n    }\n    private native int expandMedia(LibVLC libvlc_instance, int position, ArrayList<String> children);\n\n    public void loadPlaylist(String mrl) {\n        ArrayList<String> items = new ArrayList<String>();\n        loadPlaylist(mLibVLC, mrl, items);\n        this.clear();\n        for(String item : items) {\n            this.add(item);\n        }\n    }\n    private native void loadPlaylist(LibVLC libvlc_instance, String mrl, ArrayList<String> items);\n\n    public void insert(int position, String mrl) {\n        insert(position, new Media(mLibVLC, mrl));\n    }\n    public void insert(int position, Media media) {\n        mInternalList.add(position, new MediaHolder(media));\n        signal_list_event(EventHandler.CustomMediaListItemAdded, position, media.getLocation());\n    }\n\n    /**\n     * Move a media from one position to another\n     *\n     * @param startPosition start position\n     * @param endPosition end position\n     * @throws IndexOutOfBoundsException\n     */\n    public void move(int startPosition, int endPosition) {\n        if (!(isValid(startPosition)\n              && endPosition >= 0 && endPosition <= mInternalList.size()))\n            throw new IndexOutOfBoundsException(\"Indexes out of range\");\n\n        MediaHolder toMove = mInternalList.get(startPosition);\n        mInternalList.remove(startPosition);\n        if (startPosition >= endPosition)\n            mInternalList.add(endPosition, toMove);\n        else\n            mInternalList.add(endPosition - 1, toMove);\n        Bundle b = new Bundle();\n        b.putInt(\"index_before\", startPosition);\n        b.putInt(\"index_after\", endPosition);\n        mEventHandler.callback(EventHandler.CustomMediaListItemMoved, b);\n    }\n\n    public void remove(int position) {\n        if (!isValid(position))\n            return;\n        String uri = mInternalList.get(position).m.getLocation();\n        mInternalList.remove(position);\n        signal_list_event(EventHandler.CustomMediaListItemDeleted, position, uri);\n    }\n\n    public void remove(String location) {\n        for (int i = 0; i < mInternalList.size(); ++i) {\n            String uri = mInternalList.get(i).m.getLocation();\n            if (uri.equals(location)) {\n                mInternalList.remove(i);\n                signal_list_event(EventHandler.CustomMediaListItemDeleted, i, uri);\n                i--;\n            }\n        }\n    }\n\n    public int size() {\n        return mInternalList.size();\n    }\n\n    public Media getMedia(int position) {\n        if (!isValid(position))\n            return null;\n        return mInternalList.get(position).m;\n    }\n\n    /**\n     * @param position The index of the media in the list\n     * @return null if not found\n     */\n    public String getMRL(int position) {\n        if (!isValid(position))\n            return null;\n        return mInternalList.get(position).m.getLocation();\n    }\n\n    public String[] getMediaOptions(int position) {\n        boolean noHardwareAcceleration = mLibVLC.getHardwareAcceleration() == 0;\n        boolean noVideo = false;\n        if (isValid(position))\n        {\n            if (!noHardwareAcceleration)\n                noHardwareAcceleration = mInternalList.get(position).noHardwareAcceleration;\n            noVideo = mInternalList.get(position).noVideo;\n        }\n        ArrayList<String> options = new ArrayList<String>();\n\n        if (!noHardwareAcceleration) {\n            /*\n             * Set higher caching values if using iomx decoding, since some omx\n             * decoders have a very high latency, and if the preroll data isn't\n             * enough to make the decoder output a frame, the playback timing gets\n             * started too soon, and every decoded frame appears to be too late.\n             * On Nexus One, the decoder latency seems to be 25 input packets\n             * for 320x170 H.264, a few packets less on higher resolutions.\n             * On Nexus S, the decoder latency seems to be about 7 packets.\n             */\n            options.add(\":file-caching=1500\");\n            options.add(\":network-caching=1500\");\n            options.add(\":codec=mediacodec,iomx,all\");\n        }\n        if (noVideo)\n            options.add(\":no-video\");\n\n        return options.toArray(new String[options.size()]);\n    }\n\n    public EventHandler getEventHandler() {\n        return mEventHandler;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"LibVLC Media List: {\");\n        for(int i = 0; i < size(); i++) {\n            sb.append(((Integer)i).toString());\n            sb.append(\": \");\n            sb.append(getMRL(i));\n            sb.append(\", \");\n        }\n        sb.append(\"}\");\n        return sb.toString();\n    }\n\n    private void signal_list_event(int event, int position, String uri) {\n        Bundle b = new Bundle();\n        b.putString(\"item_uri\", uri);\n        b.putInt(\"item_index\", position);\n        mEventHandler.callback(event, b);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/libvlc/TrackInfo.java",
    "content": "/*****************************************************************************\n * TrackInfo.java\n *****************************************************************************\n * Copyright © 2010-2013 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as published by\n * the Free Software Foundation; either version 2.1 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.libvlc;\n\npublic class TrackInfo {\n\n    public static final int TYPE_UNKNOWN = -1;\n    public static final int TYPE_AUDIO = 0;\n    public static final int TYPE_VIDEO = 1;\n    public static final int TYPE_TEXT = 2;\n    public static final int TYPE_META = 3;\n\n    public int Type;\n    public int Id;\n    public String Codec;\n    public String Language;\n    public int Bitrate;\n\n    /* Video */\n    public int Height;\n    public int Width;\n    public float Framerate;\n\n    /* Audio */\n    public int Channels;\n    public int Samplerate;\n\n    /* MetaData */\n    public long Length;\n    public String Title;\n    public String Artist;\n    public String Album;\n    public String Genre;\n    public String ArtworkURL;\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/vlc/util/Preferences.java",
    "content": "/*****************************************************************************\n * Preferences.java\n *****************************************************************************\n * Copyright © 2011-2014 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.vlc.util;\n\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\npublic class Preferences {\n    public final static String TAG = \"VLC/Util/Preferences\";\n\n    public static float[] getFloatArray(SharedPreferences pref, String key) {\n        float[] array = null;\n        String s = pref.getString(key, null);\n        if (s != null) {\n            try {\n                JSONArray json = new JSONArray(s);\n                array = new float[json.length()];\n                for (int i = 0; i < array.length; i++)\n                    array[i] = (float) json.getDouble(i);\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        }\n        return array;\n    }\n\n    public static void putFloatArray(Editor editor, String key, float[] array) {\n        try {\n            JSONArray json = new JSONArray();\n            for (float f : array)\n                json.put(f);\n            editor.putString(\"equalizer_values\", json.toString());\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/org/videolan/vlc/util/VLCInstance.java",
    "content": "/*****************************************************************************\n * VLCInstance.java\n *****************************************************************************\n * Copyright © 2011-2014 VLC authors and VideoLAN\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\n *****************************************************************************/\n\npackage org.videolan.vlc.util;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\n\nimport com.nmbb.vlc.VLCApplication;\n\nimport org.videolan.libvlc.LibVLC;\nimport org.videolan.libvlc.LibVlcException;\n\npublic class VLCInstance {\n    public final static String TAG = \"VLC/Util/VLCInstance\";\n\n    /** A set of utility functions for the VLC application */\n    public static LibVLC getLibVlcInstance() throws LibVlcException {\n        LibVLC instance = LibVLC.getExistingInstance();\n        if (instance == null) {\n            //Thread.setDefaultUncaughtExceptionHandler(new VLCCrashHandler());\n\n            instance = LibVLC.getInstance();\n            final Context context = VLCApplication.getAppContext();\n            SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);\n            VLCInstance.updateLibVlcSettings(pref);\n            instance.init(context);\n            instance.setOnNativeCrashListener(new LibVLC.OnNativeCrashListener() {\n                @Override\n                public void onNativeCrash() {\n//                    Intent i = new Intent(context, NativeCrashActivity.class);\n//                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n//                    i.putExtra(\"PID\", android.os.Process.myPid());\n//                    context.startActivity(i);\n                \t\n//                \tLogger.e(\"[VLCInstance]onNativeCrash...\");\n                }\n            });\n        }\n        return instance;\n    }\n\n    public static void updateLibVlcSettings(SharedPreferences pref) {\n        LibVLC instance = LibVLC.getExistingInstance();\n        if (instance == null)\n            return;\n\n        instance.setSubtitlesEncoding(pref.getString(\"subtitle_text_encoding\", \"\"));\n        instance.setTimeStretching(pref.getBoolean(\"enable_time_stretching_audio\", false));\n        instance.setFrameSkip(pref.getBoolean(\"enable_frame_skip\", false));\n        instance.setChroma(pref.getString(\"chroma_format\", \"\"));\n        instance.setVerboseMode(pref.getBoolean(\"enable_verbose_mode\", true));\n\n        if (pref.getBoolean(\"equalizer_enabled\", false))\n            instance.setEqualizer(Preferences.getFloatArray(pref, \"equalizer_values\"));\n\n        int aout;\n        try {\n            aout = Integer.parseInt(pref.getString(\"aout\", \"-1\"));\n        }\n        catch (NumberFormatException nfe) {\n            aout = -1;\n        }\n        int vout;\n        try {\n        \tvout = Integer.parseInt(pref.getString(\"vout\", \"-1\"));\n        }\n        catch (NumberFormatException nfe) {\n        \tvout = -1;\n        }\n        int deblocking;\n        try {\n            deblocking = Integer.parseInt(pref.getString(\"deblocking\", \"-1\"));\n        }\n        catch(NumberFormatException nfe) {\n            deblocking = -1;\n        }\n        int hardwareAcceleration;\n        try {\n            hardwareAcceleration = Integer.parseInt(pref.getString(\"hardware_acceleration\", \"-1\"));\n        }\n        catch(NumberFormatException nfe) {\n            hardwareAcceleration = -1;\n        }\n        int networkCaching = pref.getInt(\"network_caching_value\", 0);\n        if(networkCaching > 60000)\n            networkCaching = 60000;\n        else if(networkCaching < 0)\n            networkCaching = 0;\n        instance.setAout(aout);\n        instance.setVout(vout);\n        instance.setDeblocking(deblocking);\n        instance.setNetworkCaching(networkCaching);\n        instance.setHardwareAcceleration(hardwareAcceleration);\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_video_vlc.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/video_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"horizontal\" >\n\n    <SurfaceView\n        android:id=\"@+id/video\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerInParent=\"true\"\n        android:fitsSystemWindows=\"true\" />\n\n    <LinearLayout\n        android:id=\"@+id/video_loading\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:visibility=\"visible\"\n        android:gravity=\"center_vertical\" >\n\n        <ProgressBar\n            android:id=\"@+id/video_loading_progress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/video_loading_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"7.0dip\"\n            android:text=\"@string/video_layout_loading\"\n            android:textColor=\"@android:color/white\"\n            android:textSize=\"20.0sp\" />\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">VLC-Demo</string>\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"video_layout_loading\">Loading...</string>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Light\">\n        <!-- Customize your theme here. -->\n    </style>\n\n    <!-- Application theme. -->\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowFullscreen\">true</item>\n    </style>\n\n    <style name=\"VideoTheme\" parent=\"AppBaseTheme\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowFullscreen\">true</item>\n        <item name=\"android:windowBackground\">@android:color/black</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:0.12.2'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Settings specified in this file will override any Gradle settings\n# configured through the IDE.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]