[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <Objective-C-extensions>\n      <file>\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Import\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Macro\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Typedef\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Enum\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Constant\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Global\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Struct\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"FunctionPredecl\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Function\" />\n      </file>\n      <class>\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Property\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Synthesize\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InitMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"StaticMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InstanceMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"DeallocMethod\" />\n      </class>\n      <extensions>\n        <pair source=\"cpp\" header=\"h\" fileNamingConvention=\"NONE\" />\n        <pair source=\"c\" header=\"h\" fileNamingConvention=\"NONE\" />\n      </extensions>\n    </Objective-C-extensions>\n  </code_scheme>\n</component>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <compositeConfiguration>\n          <compositeBuild compositeDefinitionSource=\"SCRIPT\" />\n        </compositeConfiguration>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CMakeSettings\">\n    <configurations>\n      <configuration PROFILE_NAME=\"Debug\" CONFIG_NAME=\"Debug\" />\n    </configurations>\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "<img class=\"card-img-top\" src=\"https://codingwithmitch.s3.amazonaws.com/static/blog/edab666e-36cf-11e9-b183-2aabe8ede8eb/playing_video_in_recyclerview_with_exoplayer.png\">\n<br>\n<h1>Playing Video in a RecyclerView with ExoPlayer</h1>\nRead the blog post for a guide: <a href=\"https://codingwithmitch.com/blog/playing-video-recyclerview-exoplayer-android/\" target=\"_blank\">Blog Post</a>\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n    defaultConfig {\n        applicationId \"com.codingwithmitch.recyclerviewvideoplayer\"\n        minSdkVersion 21\n        targetSdkVersion 28\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    def supportVersion = \"28.0.0\"\n    def glideVersion = \"4.9.0\"\n\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation \"com.android.support:appcompat-v7:$supportVersion\"\n    implementation 'com.android.support.constraint:constraint-layout:1.1.3'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.2'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'\n\n\n    // Recyclerview\n    implementation \"com.android.support:recyclerview-v7:$supportVersion\"\n\n    // ExoPlayer\n    implementation 'com.google.android.exoplayer:exoplayer:2.8.4' // 2.9.0 has min sdk 26\n\n    implementation \"com.github.bumptech.glide:glide:$glideVersion\"\n    annotationProcessor \"com.github.bumptech.glide:compiler:$glideVersion\"\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/com/codingwithmitch/recyclerviewvideoplayer/ExampleInstrumentedTest.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.codingwithmitch.recyclerviewvideoplayer\", appContext.getPackageName());\n    }\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.codingwithmitch.recyclerviewvideoplayer\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\">\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>"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/MainActivity.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.RequestManager;\nimport com.bumptech.glide.request.RequestOptions;\nimport com.codingwithmitch.recyclerviewvideoplayer.models.MediaObject;\nimport com.codingwithmitch.recyclerviewvideoplayer.util.Resources;\nimport com.codingwithmitch.recyclerviewvideoplayer.util.VerticalSpacingItemDecorator;\n\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\npublic class MainActivity extends AppCompatActivity {\n\n    private static final String TAG = \"MainActivity\";\n\n    private VideoPlayerRecyclerView mRecyclerView;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        mRecyclerView = findViewById(R.id.recycler_view);\n\n        initRecyclerView();\n    }\n\n    private void initRecyclerView(){\n        LinearLayoutManager layoutManager = new LinearLayoutManager(this);\n        mRecyclerView.setLayoutManager(layoutManager);\n        VerticalSpacingItemDecorator itemDecorator = new VerticalSpacingItemDecorator(10);\n        mRecyclerView.addItemDecoration(itemDecorator);\n\n        ArrayList<MediaObject> mediaObjects = new ArrayList<MediaObject>(Arrays.asList(Resources.MEDIA_OBJECTS));\n        mRecyclerView.setMediaObjects(mediaObjects);\n        VideoPlayerRecyclerAdapter adapter = new VideoPlayerRecyclerAdapter(mediaObjects, initGlide());\n        mRecyclerView.setAdapter(adapter);\n    }\n\n    private RequestManager initGlide(){\n        RequestOptions options = new RequestOptions()\n                .placeholder(R.drawable.white_background)\n                .error(R.drawable.white_background);\n\n        return Glide.with(this)\n                .setDefaultRequestOptions(options);\n    }\n\n\n    @Override\n    protected void onDestroy() {\n        if(mRecyclerView!=null)\n            mRecyclerView.releasePlayer();\n        super.onDestroy();\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/VideoPlayerRecyclerAdapter.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer;\n\nimport android.support.annotation.NonNull;\nimport android.support.v7.widget.RecyclerView;\n\nimport android.view.LayoutInflater;\nimport android.view.ViewGroup;\n\nimport com.bumptech.glide.RequestManager;\nimport com.codingwithmitch.recyclerviewvideoplayer.models.MediaObject;\n\nimport java.util.ArrayList;\n\n\npublic class VideoPlayerRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {\n\n    private ArrayList<MediaObject> mediaObjects;\n    private RequestManager requestManager;\n\n\n    public VideoPlayerRecyclerAdapter(ArrayList<MediaObject> mediaObjects, RequestManager requestManager) {\n        this.mediaObjects = mediaObjects;\n        this.requestManager = requestManager;\n    }\n\n    @NonNull\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {\n        return new VideoPlayerViewHolder(\n                LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_video_list_item, viewGroup, false));\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {\n        ((VideoPlayerViewHolder)viewHolder).onBind(mediaObjects.get(i), requestManager);\n    }\n    \n    @Override\n    public int getItemCount() {\n        return mediaObjects.size();\n    }\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/VideoPlayerRecyclerView.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer;\n\n\nimport android.animation.Animator;\nimport android.content.Context;\nimport android.graphics.Point;\nimport android.net.Uri;\nimport android.os.Handler;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Display;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.WindowManager;\n\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\n\nimport com.bumptech.glide.RequestManager;\nimport com.codingwithmitch.recyclerviewvideoplayer.models.MediaObject;\nimport com.google.android.exoplayer2.DefaultLoadControl;\nimport com.google.android.exoplayer2.ExoPlaybackException;\nimport com.google.android.exoplayer2.ExoPlayerFactory;\nimport com.google.android.exoplayer2.LoadControl;\nimport com.google.android.exoplayer2.PlaybackParameters;\nimport com.google.android.exoplayer2.Player;\nimport com.google.android.exoplayer2.SimpleExoPlayer;\nimport com.google.android.exoplayer2.Timeline;\nimport com.google.android.exoplayer2.source.ExtractorMediaSource;\nimport com.google.android.exoplayer2.source.MediaSource;\nimport com.google.android.exoplayer2.source.TrackGroupArray;\nimport com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;\nimport com.google.android.exoplayer2.trackselection.DefaultTrackSelector;\nimport com.google.android.exoplayer2.trackselection.TrackSelection;\nimport com.google.android.exoplayer2.trackselection.TrackSelectionArray;\nimport com.google.android.exoplayer2.trackselection.TrackSelector;\nimport com.google.android.exoplayer2.ui.AspectRatioFrameLayout;\nimport com.google.android.exoplayer2.ui.PlayerView;\nimport com.google.android.exoplayer2.upstream.BandwidthMeter;\nimport com.google.android.exoplayer2.upstream.DataSource;\nimport com.google.android.exoplayer2.upstream.DefaultAllocator;\nimport com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;\nimport com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;\nimport com.google.android.exoplayer2.util.Util;\n\n\nimport java.util.ArrayList;\n\npublic class VideoPlayerRecyclerView extends RecyclerView {\n\n    private static final String TAG = \"VideoPlayerRecyclerView\";\n\n    private enum VolumeState {ON, OFF};\n\n    // ui\n    private ImageView thumbnail, volumeControl;\n    private ProgressBar progressBar;\n    private View viewHolderParent;\n    private FrameLayout frameLayout;\n    private PlayerView videoSurfaceView;\n    private SimpleExoPlayer videoPlayer;\n\n    // vars\n    private ArrayList<MediaObject> mediaObjects = new ArrayList<>();\n    private int videoSurfaceDefaultHeight = 0;\n    private int screenDefaultHeight = 0;\n    private Context context;\n    private int playPosition = -1;\n    private boolean isVideoViewAdded;\n    private RequestManager requestManager;\n\n    // controlling playback state\n    private VolumeState volumeState;\n\n    public VideoPlayerRecyclerView(@NonNull Context context) {\n        super(context);\n        init(context);\n    }\n\n    public VideoPlayerRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        init(context);\n    }\n\n\n    private void init(Context context){\n        this.context = context.getApplicationContext();\n        Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();\n        Point point = new Point();\n        display.getSize(point);\n        videoSurfaceDefaultHeight = point.x;\n        screenDefaultHeight = point.y;\n\n        videoSurfaceView = new PlayerView(this.context);\n        videoSurfaceView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM);\n\n        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();\n        TrackSelection.Factory videoTrackSelectionFactory =\n                new AdaptiveTrackSelection.Factory(bandwidthMeter);\n        TrackSelector trackSelector =\n                new DefaultTrackSelector(videoTrackSelectionFactory);\n\n        // 2. Create the player\n        videoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);\n        // Bind the player to the view.\n        videoSurfaceView.setUseController(false);\n        videoSurfaceView.setPlayer(videoPlayer);\n        setVolumeControl(VolumeState.ON);\n\n        addOnScrollListener(new RecyclerView.OnScrollListener() {\n            @Override\n            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {\n                super.onScrollStateChanged(recyclerView, newState);\n\n                if (newState == RecyclerView.SCROLL_STATE_IDLE) {\n                    Log.d(TAG, \"onScrollStateChanged: called.\");\n                    if(thumbnail != null){ // show the old thumbnail\n                        thumbnail.setVisibility(VISIBLE);\n                    }\n\n                    // There's a special case when the end of the list has been reached.\n                    // Need to handle that with this bit of logic\n                    if(!recyclerView.canScrollVertically(1)){\n                        playVideo(true);\n                    }\n                    else{\n                        playVideo(false);\n                    }\n                }\n            }\n\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                super.onScrolled(recyclerView, dx, dy);\n            }\n        });\n\n        addOnChildAttachStateChangeListener(new OnChildAttachStateChangeListener() {\n            @Override\n            public void onChildViewAttachedToWindow(View view) {\n\n            }\n\n            @Override\n            public void onChildViewDetachedFromWindow(View view) {\n                if (viewHolderParent != null && viewHolderParent.equals(view)) {\n                    resetVideoView();\n                }\n\n            }\n        });\n\n        videoPlayer.addListener(new Player.EventListener() {\n            @Override\n            public void onTimelineChanged(Timeline timeline, @Nullable Object manifest, int reason) {\n\n            }\n\n            @Override\n            public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {\n\n            }\n\n            @Override\n            public void onLoadingChanged(boolean isLoading) {\n\n            }\n\n            @Override\n            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {\n                switch (playbackState) {\n\n                    case Player.STATE_BUFFERING:\n                        Log.e(TAG, \"onPlayerStateChanged: Buffering video.\");\n                        if (progressBar != null) {\n                            progressBar.setVisibility(VISIBLE);\n                        }\n\n                        break;\n                    case Player.STATE_ENDED:\n                        Log.d(TAG, \"onPlayerStateChanged: Video ended.\");\n                        videoPlayer.seekTo(0);\n                        break;\n                    case Player.STATE_IDLE:\n\n                        break;\n                    case Player.STATE_READY:\n                        Log.e(TAG, \"onPlayerStateChanged: Ready to play.\");\n                        if (progressBar != null) {\n                            progressBar.setVisibility(GONE);\n                        }\n                        if(!isVideoViewAdded){\n                            addVideoView();\n                        }\n                        break;\n                    default:\n                        break;\n                }\n            }\n\n            @Override\n            public void onRepeatModeChanged(int repeatMode) {\n\n            }\n\n            @Override\n            public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {\n\n            }\n\n            @Override\n            public void onPlayerError(ExoPlaybackException error) {\n\n            }\n\n            @Override\n            public void onPositionDiscontinuity(int reason) {\n\n            }\n\n            @Override\n            public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {\n\n            }\n\n            @Override\n            public void onSeekProcessed() {\n\n            }\n        });\n    }\n\n    public void playVideo(boolean isEndOfList) {\n\n        int targetPosition;\n\n        if(!isEndOfList){\n            int startPosition = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();\n            int endPosition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();\n\n            // if there is more than 2 list-items on the screen, set the difference to be 1\n            if (endPosition - startPosition > 1) {\n                endPosition = startPosition + 1;\n            }\n\n            // something is wrong. return.\n            if (startPosition < 0 || endPosition < 0) {\n                return;\n            }\n\n            // if there is more than 1 list-item on the screen\n            if (startPosition != endPosition) {\n                int startPositionVideoHeight = getVisibleVideoSurfaceHeight(startPosition);\n                int endPositionVideoHeight = getVisibleVideoSurfaceHeight(endPosition);\n\n                targetPosition = startPositionVideoHeight > endPositionVideoHeight ? startPosition : endPosition;\n            }\n            else {\n                targetPosition = startPosition;\n            }\n        }\n        else{\n            targetPosition = mediaObjects.size() - 1;\n        }\n\n        Log.d(TAG, \"playVideo: target position: \" + targetPosition);\n\n        // video is already playing so return\n        if (targetPosition == playPosition) {\n            return;\n        }\n\n        // set the position of the list-item that is to be played\n        playPosition = targetPosition;\n        if (videoSurfaceView == null) {\n            return;\n        }\n\n        // remove any old surface views from previously playing videos\n        videoSurfaceView.setVisibility(INVISIBLE);\n        removeVideoView(videoSurfaceView);\n\n        int currentPosition = targetPosition - ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();\n\n        View child = getChildAt(currentPosition);\n        if (child == null) {\n            return;\n        }\n\n        VideoPlayerViewHolder holder = (VideoPlayerViewHolder) child.getTag();\n        if (holder == null) {\n            playPosition = -1;\n            return;\n        }\n        thumbnail = holder.thumbnail;\n        progressBar = holder.progressBar;\n        volumeControl = holder.volumeControl;\n        viewHolderParent = holder.itemView;\n        requestManager = holder.requestManager;\n        frameLayout = holder.itemView.findViewById(R.id.media_container);\n\n        videoSurfaceView.setPlayer(videoPlayer);\n\n        viewHolderParent.setOnClickListener(videoViewClickListener);\n\n        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(\n                context, Util.getUserAgent(context, \"RecyclerView VideoPlayer\"));\n        String mediaUrl = mediaObjects.get(targetPosition).getMedia_url();\n        if (mediaUrl != null) {\n            MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)\n                    .createMediaSource(Uri.parse(mediaUrl));\n            videoPlayer.prepare(videoSource);\n            videoPlayer.setPlayWhenReady(true);\n        }\n    }\n\n    private OnClickListener videoViewClickListener = new OnClickListener() {\n        @Override\n        public void onClick(View v) {\n            toggleVolume();\n        }\n    };\n\n    /**\n     * Returns the visible region of the video surface on the screen.\n     * if some is cut off, it will return less than the @videoSurfaceDefaultHeight\n     * @param playPosition\n     * @return\n     */\n    private int getVisibleVideoSurfaceHeight(int playPosition) {\n        int at = playPosition - ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();\n        Log.d(TAG, \"getVisibleVideoSurfaceHeight: at: \" + at);\n\n        View child = getChildAt(at);\n        if (child == null) {\n            return 0;\n        }\n\n        int[] location = new int[2];\n        child.getLocationInWindow(location);\n\n        if (location[1] < 0) {\n            return location[1] + videoSurfaceDefaultHeight;\n        } else {\n            return screenDefaultHeight - location[1];\n        }\n    }\n\n\n    // Remove the old player\n    private void removeVideoView(PlayerView videoView) {\n        ViewGroup parent = (ViewGroup) videoView.getParent();\n        if (parent == null) {\n            return;\n        }\n\n        int index = parent.indexOfChild(videoView);\n        if (index >= 0) {\n            parent.removeViewAt(index);\n            isVideoViewAdded = false;\n            viewHolderParent.setOnClickListener(null);\n        }\n\n    }\n\n    private void addVideoView(){\n        frameLayout.addView(videoSurfaceView);\n        isVideoViewAdded = true;\n        videoSurfaceView.requestFocus();\n        videoSurfaceView.setVisibility(VISIBLE);\n        videoSurfaceView.setAlpha(1);\n        thumbnail.setVisibility(GONE);\n    }\n\n    private void resetVideoView(){\n        if(isVideoViewAdded){\n            removeVideoView(videoSurfaceView);\n            playPosition = -1;\n            videoSurfaceView.setVisibility(INVISIBLE);\n            thumbnail.setVisibility(VISIBLE);\n        }\n    }\n\n    public void releasePlayer() {\n\n        if (videoPlayer != null) {\n            videoPlayer.release();\n            videoPlayer = null;\n        }\n\n        viewHolderParent = null;\n    }\n\n    private void toggleVolume() {\n        if (videoPlayer != null) {\n            if (volumeState == VolumeState.OFF) {\n                Log.d(TAG, \"togglePlaybackState: enabling volume.\");\n                setVolumeControl(VolumeState.ON);\n\n            } else if(volumeState == VolumeState.ON) {\n                Log.d(TAG, \"togglePlaybackState: disabling volume.\");\n                setVolumeControl(VolumeState.OFF);\n\n            }\n        }\n    }\n\n    private void setVolumeControl(VolumeState state){\n        volumeState = state;\n        if(state == VolumeState.OFF){\n            videoPlayer.setVolume(0f);\n            animateVolumeControl();\n        }\n        else if(state == VolumeState.ON){\n            videoPlayer.setVolume(1f);\n            animateVolumeControl();\n        }\n    }\n\n    private void animateVolumeControl(){\n        if(volumeControl != null){\n            volumeControl.bringToFront();\n            if(volumeState == VolumeState.OFF){\n                requestManager.load(R.drawable.ic_volume_off_grey_24dp)\n                        .into(volumeControl);\n            }\n            else if(volumeState == VolumeState.ON){\n                requestManager.load(R.drawable.ic_volume_up_grey_24dp)\n                        .into(volumeControl);\n            }\n            volumeControl.animate().cancel();\n\n            volumeControl.setAlpha(1f);\n\n            volumeControl.animate()\n                    .alpha(0f)\n                    .setDuration(600).setStartDelay(1000);\n        }\n    }\n\n    public void setMediaObjects(ArrayList<MediaObject> mediaObjects){\n        this.mediaObjects = mediaObjects;\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/VideoPlayerViewHolder.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer;\n\nimport android.support.annotation.NonNull;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport com.bumptech.glide.RequestManager;\nimport com.codingwithmitch.recyclerviewvideoplayer.models.MediaObject;\n\n\npublic class VideoPlayerViewHolder extends RecyclerView.ViewHolder {\n\n    FrameLayout media_container;\n    TextView title;\n    ImageView thumbnail, volumeControl;\n    ProgressBar progressBar;\n    View parent;\n    RequestManager requestManager;\n\n    public VideoPlayerViewHolder(@NonNull View itemView) {\n        super(itemView);\n        parent = itemView;\n        media_container = itemView.findViewById(R.id.media_container);\n        thumbnail = itemView.findViewById(R.id.thumbnail);\n        title = itemView.findViewById(R.id.title);\n        progressBar = itemView.findViewById(R.id.progressBar);\n        volumeControl = itemView.findViewById(R.id.volume_control);\n    }\n\n    public void onBind(MediaObject mediaObject, RequestManager requestManager) {\n        this.requestManager = requestManager;\n        parent.setTag(this);\n        title.setText(mediaObject.getTitle());\n        this.requestManager\n                .load(mediaObject.getThumbnail())\n                .into(thumbnail);\n    }\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/models/MediaObject.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer.models;\n\npublic class MediaObject {\n\n    private String title;\n    private String media_url;\n    private String thumbnail;\n    private String description;\n\n    public MediaObject(String title, String media_url, String thumbnail, String description) {\n        this.title = title;\n        this.media_url = media_url;\n        this.thumbnail = thumbnail;\n        this.description = description;\n    }\n\n    public MediaObject() {\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public String getMedia_url() {\n        return media_url;\n    }\n\n    public void setMedia_url(String media_url) {\n        this.media_url = media_url;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    public String getThumbnail() {\n        return thumbnail;\n    }\n\n    public void setThumbnail(String thumbnail) {\n        this.thumbnail = thumbnail;\n    }\n}\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/util/Resources.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer.util;\n\nimport com.codingwithmitch.recyclerviewvideoplayer.models.MediaObject;\n\npublic class Resources {\n\n    public static final MediaObject[] MEDIA_OBJECTS = {\n            new MediaObject(\"Sending Data to a New Activity with Intent Extras\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/Sending+Data+to+a+New+Activity+with+Intent+Extras.mp4\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/Sending+Data+to+a+New+Activity+with+Intent+Extras.png\",\n                    \"Description for media object #1\"),\n            new MediaObject(\"REST API, Retrofit2, MVVM Course SUMMARY\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/REST+API+Retrofit+MVVM+Course+Summary.mp4\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/REST+API%2C+Retrofit2%2C+MVVM+Course+SUMMARY.png\",\n                    \"Description for media object #2\"),\n            new MediaObject(\"MVVM and LiveData\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/MVVM+and+LiveData+for+youtube.mp4\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/mvvm+and+livedata.png\",\n                    \"Description for media object #3\"),\n            new MediaObject(\"Swiping Views with a ViewPager\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/SwipingViewPager+Tutorial.mp4\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/Swiping+Views+with+a+ViewPager.png\",\n                    \"Description for media object #4\"),\n            new MediaObject(\"Database Cache, MVVM, Retrofit, REST API demo for upcoming course\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/Rest+api+teaser+video.mp4\",\n                    \"https://s3.ca-central-1.amazonaws.com/codingwithmitch/media/VideoPlayerRecyclerView/Rest+API+Integration+with+MVVM.png\",\n                    \"Description for media object #5\"),\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/com/codingwithmitch/recyclerviewvideoplayer/util/VerticalSpacingItemDecorator.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer.util;\n\nimport android.graphics.Rect;\nimport android.support.annotation.NonNull;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\npublic class VerticalSpacingItemDecorator extends RecyclerView.ItemDecoration {\n\n    private final int verticalSpaceHeight;\n\n    public VerticalSpacingItemDecorator(int verticalSpaceHeight) {\n        this.verticalSpaceHeight = verticalSpaceHeight;\n    }\n\n    @Override\n    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {\n\n        outRect.top = verticalSpaceHeight;\n    }\n}"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#008577\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_volume_off_grey_24dp.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#686868\"\n    android:viewportHeight=\"24.0\" android:viewportWidth=\"24.0\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_volume_up_grey_24dp.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#686868\"\n    android:viewportHeight=\"24.0\" android:viewportWidth=\"24.0\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.constraint.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".MainActivity\"\n    android:background=\"#f2f2f2\">\n\n    <com.codingwithmitch.recyclerviewvideoplayer.VideoPlayerRecyclerView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:id=\"@+id/recycler_view\"\n        android:orientation=\"vertical\">\n\n    </com.codingwithmitch.recyclerviewvideoplayer.VideoPlayerRecyclerView>\n\n</android.support.constraint.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/layout/layout_video_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.constraint.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:weightSum=\"100\"\n    android:id=\"@+id/parent\"\n    android:background=\"#fff\">\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"10dp\"\n        android:layout_marginEnd=\"10dp\"\n        android:layout_marginBottom=\"15dp\"\n        android:padding=\"10dp\"\n        android:textColor=\"#000\"\n        android:textSize=\"20sp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/media_container\"\n        android:text=\"This is the title\"/>\n\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/title\"\n        android:background=\"#000\"\n        android:scaleType=\"center\"\n        android:id=\"@+id/media_container\">\n\n        <ImageView\n            android:id=\"@+id/thumbnail\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"#fff\"\n            android:scaleType=\"centerInside\"\n            android:src=\"@drawable/white_background\" />\n\n        <ImageView\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/ic_volume_up_grey_24dp\"\n            android:layout_gravity=\"end|bottom\"\n            android:id=\"@+id/volume_control\"\n            android:alpha=\"0\"\n            android:animateLayoutChanges=\"true\"\n            android:layout_marginEnd=\"15dp\"\n            android:layout_marginBottom=\"15dp\"/>\n\n        <ProgressBar\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:id=\"@+id/progressBar\"\n            style=\"?android:attr/progressBarStyle\"\n            android:visibility=\"gone\"\n            android:layout_gravity=\"center\" />\n\n\n    </FrameLayout>\n\n\n\n</android.support.constraint.ConstraintLayout>\n\n\n\n\n\n\n"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"colorPrimaryDark\">#00574B</color>\n    <color name=\"colorAccent\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">RecyclerViewVideoPlayer</string>\n    <string name=\"dummy_title\">What is Lorem Ipsum?</string>\n    <string name=\"dummy_description\">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/test/java/com/codingwithmitch/recyclerviewvideoplayer/ExampleUnitTest.java",
    "content": "package com.codingwithmitch.recyclerviewvideoplayer;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() {\n        assertEquals(4, 2 + 2);\n    }\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        google()\n        jcenter()\n        \n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.3.0'\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        google()\n        jcenter()\n        \n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Feb 20 09:15:38 PST 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.10.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\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\n\n\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]