Playing a full screen video in an android app the easy way.

The Android sdk has a MediaPlayer api that should make it easy to play videos. There is, however, a much easier way.

VideoView makes it super simple to play videos. Here’s how we use it.

The XML files

First, add a VideoView to the activities xml file. We’ll call it videoplayer.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <VideoView
        android:id="@+id/myvideoview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"
    />
</LinearLayout>

We set the LinearLayout to horizontal orientation in this case because my videos are all landscape. We set the layout’s to “fill_parent” so our VideoView takes up the whole parents view. We don’t want to stretch it out of proportion, but we do want the video centered, so we set the layout_gravity to “center”.

We also need to update the AndroidManifest.xml file to make sure our VideoPlayer activity is full screen (using theme), stays in landscape orientation (using screenOrientation) and only has one instance, so we don’t get a bunch of video players running. (launchMode)

    <activity
        android:name=".VideoPlayer" 
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
        android:screenOrientation="landscape" ></activity>

Calling code

When we want to show a full screen video, we’ll do it by creating the intent for the VideoPlayer activity, grabbing the video resource id, pass it to the VideoPlayer activity, and start the activity:

private void playVideo(String resourceName) {
    Intent videoPlaybackActivity = new Intent(this, VideoPlayer.class);
    int res=this.getResources().getIdentifier(resourceName, "raw", getPackageName());
    videoPlaybackActivity.putExtra("fileRes", res);
    startActivity(videoPlaybackActivity);
}

The VideoPlayer Activity code

Now we can get to the VideoPlayer activity code. It turns out to be not that complex. Here’s VideoPlayer.java:

public class VideoPlayer extends Activity implements OnCompletionListener {
		   
    private VideoView mVV;
		 
    @Override
    public void onCreate(Bundle b) {
        super.onCreate(b);

        setContentView(R.layout.videoplayer);

        int fileRes=0;     
        Bundle e = getIntent().getExtras();
        if (e!=null) {
            fileRes = e.getInt("fileRes");
        }

        mVV = (VideoView)findViewById(R.id.myvideoview);
        mVV.setOnCompletionListener(this);
        mVV.setOnPreparedListener(this);
        mVV.setOnTouchListener(this);

        if (!playFileRes(fileRes)) return;

        mVV.start();
    }
		 
    private boolean playFileRes(int fileRes) {
        if (fileRes==0) {
            stopPlaying();
            return false;
        } else {
            mVV.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + fileRes));
            return true;
        }
    }

    public void stopPlaying() {
        mVV.stopPlayback();
        this.finish();		    	
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        finish();
    }
}

It’s pretty simple. We set the VideoView’s video URI to point to the resource id passed (if it exists), and start playing. If it doesn’t exist, we exit.

Playing new video files

Since we added the singleLaunch taskMode to the activity, that means that if we attempt to launch the VideoPlayer activity while its still running, onCreate() won’t be called, so it won’t know that its supposed to be playing a different video. In this case, the onNewIntent() function will be called with the new intent. We simply parse the extras bundle to get the file resource, if any, and it will play the new file:

    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        int fileRes = 0;
        Bundle e = getIntent().getExtras();
        if (e != null) {
            fileRes = e.getInt("fileRes");
        }
        playFileRes(fileRes);
    }

Making the video loop

We would also like our video to loop until we stop it. The best place to do this is once the MediaPlayer has been prepared. We add OnPreparedListener to the implements list of the VideoPlayer activity, and a simple onPrepared function that simply sets our MediaPlayer instance to looping:

public class VideoPlayer extends Activity implements OnCompletionListener,OnPreparedListener {
...
    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.setLooping(true);
    }
...
}

Stopping at a Touch

We would also like to be able to stop the video with a tap on the screen, so we add OnTouchListener to the implements list of the VideoPlayer activity, and a simple onTouch function that simply calls our stopPlaying() function:

public class VideoPlayer extends Activity implements OnCompletionListener,OnPreparedListener,OnTouchListener {
...
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        stopPlaying();
        return true;
    }
...
}

Complete Java Source

Here’s the complete source, in case you missed any additions:

public class VideoPlayer extends Activity implements OnCompletionListener,OnPreparedListener,OnTouchListener {
		   
    private VideoView mVV;
		 
    @Override
    public void onCreate(Bundle b) {
        super.onCreate(b);

        setContentView(R.layout.videoplayer);

        int fileRes=0;     
        Bundle e = getIntent().getExtras();
        if (e!=null) {
            fileRes = e.getInt("fileRes");
        }

        mVV = (VideoView)findViewById(R.id.myvideoview);
        mVV.setOnCompletionListener(this);
        mVV.setOnPreparedListener(this);
        mVV.setOnTouchListener(this);

        if (!playFileRes(fileRes)) return;

        mVV.start();
    }
		 
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        int fileRes = 0;
        Bundle e = getIntent().getExtras();
        if (e != null) {
            fileRes = e.getInt("fileRes");
        }
        playFileRes(fileRes);
    }
		    
    private boolean playFileRes(int fileRes) {
        if (fileRes==0) {
            stopPlaying();
            return false;
        } else {
            mVV.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + fileRes));
            return true;
        }
    }

    public void stopPlaying() {
        mVV.stopPlayback();
        this.finish();		    	
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        finish();
    }
			
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        stopPlaying();
        return true;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.setLooping(true);
    }
}

Making a single-instance android app with Intents

If you have Intents that you want to react to in your android app, but you don’t want each new Intent to launch a new instance of your android app, you can make it single instance by adding the following to your main activity’s section in your AndroidManifest.xml:

  android:launchMode="singleInstance"

When you do this, instead of processing your intents in onCreate(), you process it in onNewIntent():

@Override
protected void onNewIntent(Intent intent) {
  // ... process the intent
}