Wednesday, May 18, 2011

How to create custom dialog to play video in android


It all began when i needed to play a video from HTML5 page inside android's native browser running on android version 2.2 OS. After several attempts of playing the video via a much awaited <video> tag of HTML i realized that probably  an android 2.2 device is not capable of handling the <video> tag. Hence i rested my case, and started creating my own 'custom android dialog' for playing video.

Here are the steps to create and show the dialog from HTML5 page:

Step1. Create a subclass of Dialog.


package com.om.wv;


import java.io.IOException;
import android.app.Dialog;
import android.content.Context;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;


public class VideoPopup extends Dialog implements SurfaceHolder.Callback 
{
    MediaPlayer mediaPlayer;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    boolean pausing = false;;
    String videoPath = "";
    String videoName = "";
    
    public VideoPopup(Context context, final String name, final String path) 
    {
        super(context);
        this.videoName = name;
        this.videoPath = path;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.custom_dialog);
        setTitle(this.videoName);
        
        //------ ------ ------
        Button buttonStartVideo = (Button)findViewById(R.id.start_button);
        Button buttonPauseVideo = (Button)findViewById(R.id.pause_button);
        Button buttonStopVideo = (Button)findViewById(R.id.end_button);
     
        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView)findViewById(R.id.videoElem);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mediaPlayer = new MediaPlayer();
     
        //Handle the click-event on start button
        buttonStartVideo.setOnClickListener(new Button.OnClickListener(){


  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub
   pausing = false;

   if(mediaPlayer.isPlaying()){
    mediaPlayer.reset();
   }

   mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
   mediaPlayer.setDisplay(surfaceHolder);

   try {
    mediaPlayer.setDataSource(videoPath);
    mediaPlayer.prepare();
   } catch (IllegalArgumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IllegalStateException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   mediaPlayer.start();
  }});


        //Handle the click-event on pause button
        buttonPauseVideo.setOnClickListener(new Button.OnClickListener(){


        @Override
        public void onClick(View v) {
         
        if(pausing){
         pausing = false;
         mediaPlayer.start();
        } else{
         pausing = true;
         mediaPlayer.pause();
        }
        }}); 
        
        //Handle the click-event on stop button
        buttonStopVideo.setOnClickListener(new Button.OnClickListener(){
        @Override
        public void onClick(View v) { mediaPlayer.stop(); }}); 
        
    }


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }


    @Override
    public void surfaceCreated(SurfaceHolder holder) { }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) { }


}

Step2. Create an activity class that will extend 'Activity'

package com.om.wv;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class WebVideoActivity extends Activity 
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webviewlayout);
        
        WebView myWebView = (WebView) findViewById(R.id.webview);
    WebSettings myWebSettings = myWebView.getSettings();
   
    myWebSettings.setJavaScriptEnabled(true);
    myWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    myWebSettings.setDatabaseEnabled(true);
    myWebSettings.setAllowFileAccess(true);
   
    //create and add a Javascript interface
    MyJavascriptInterface js = new MyJavascriptInterface(this);
    myWebView.addJavascriptInterface(js, "Android");
   
    // provision for alert
    myWebView.setWebChromeClient(new WebChromeClient());
   
    myWebView.loadUrl("file:///android_asset/html/test.html");

    }
}

class MyJavascriptInterface 
{
private static final String TAG = "WebVideoActivity";
private WebVideoActivity wvActivity;
protected MyJavascriptInterface(WebVideoActivity wvActivity)
{
this.wvActivity = wvActivity;
}
    //Function that will be called from javascript as Android.showVideo('your vid name','/sdcard/urVideo.mp4')
    public void showVideo(final String videoName, final String videoPath)
    {
    VideoPopup videoPopup = new VideoPopup(wvActivity, videoName, videoPath);
    videoPopup.show();
    }

}

Step 3. Create XML for the custom layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
   
   <VideoView android:id="@+id/videoElem"
    android:layout_width="fill_parent"
    android:layout_height="160dip">
    </VideoView>
    
  </LinearLayout>
  
  
  <LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:gravity="center"
    android:padding="0dip"
    android:background="@drawable/cusombutton">
    
    <Button
      android:id="@+id/start_button"
      android:layout_width="wrap_content"
      android:layout_height="50dip"
      android:text=" Start "
      android:textSize="12dip" />
      
     <Button
      android:id="@+id/pause_button"
      android:layout_width="wrap_content"
      android:layout_height="50dip"
      android:text=" Pause " 
      android:textSize="12dip" />
      
    <Button
      android:id="@+id/end_button"
      android:layout_width="wrap_content"
      android:layout_height="50dip"
      android:text=" Stop " 
      android:textSize="12dip" />
  </LinearLayout>
  
</LinearLayout>

Step4. Create an HTML5 file as test.html in asset>html> and make a javascript call to showVideo()
whenever you feel appropriate i.e. onclick()/onLoad()/onXXX 

Also include an additional XML for rounded corners of buttons inside our video popup as

<?xml version="1.0" encoding="UTF-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
     android:shape="rectangle"> 

    <corners android:bottomRightRadius="10dip" android:bottomLeftRadius="10dip" 
     android:topLeftRadius="10dip" android:topRightRadius="10dip"/> 
</shape> 

That's it you are ready to rock and roll. 




2 comments:

Jonathan Yarkoni said...

final Context con=this;
new VideoPopup(con,"myvideo","path of url").show();

could u further specify how to create the HTML5 file and whether and how is it possible to use a video from res folder or phone.

Anonymous said...

Thanks a ton! My code gave me an IllegalArgumentException when I tried to set the surfaceHolder in the mediaPlayer right after I initialized it. As per your implementation I implement callback and I'm setting the surfaceHolder right before start() and it doesn't throw the exception.