Search...

Thursday, December 1, 2011

How to create custom MediaController in honeycomb android


(1)custom_video.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">

<com.code.EnhancedSurfaceView
android:id="@+id/video_player_surface" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_gravity="center">

</com.code.EnhancedSurfaceView>


<RelativeLayout android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="@+id/top_panel"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="horizontal" android:background="#40808080"
android:visibility="visible" android:layout_alignParentTop="true">
<TextView android:id="@+id/video_player_caption"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:textSize="20dip" android:textStyle="bold" android:gravity="center" />
</LinearLayout>
<ProgressBar android:id="@+id/progress1"
android:layout_height="60px" android:layout_width="60px"
android:indeterminate="true" android:visibility="visible"
android:layout_centerHorizontal="true" android:layout_centerVertical="true"
android:layout_below="@+id/IVsetup1"></ProgressBar>
<LinearLayout android:id="@+id/bottom_panel"
android:layout_height="wrap_content" android:layout_width="fill_parent"
android:background="#40808080" android:layout_alignParentBottom="true"
android:orientation="vertical" android:gravity="center_horizontal">

<LinearLayout android:id="@+id/bottom_panel1"
android:layout_height="wrap_content" android:layout_width="fill_parent"
android:layout_alignParentBottom="true" android:orientation="horizontal"
android:gravity="center_horizontal">
<ImageButton android:id="@+id/mediaRew"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_centerHorizontal="true" android:background="@android:drawable/ic_media_rew" />
<ImageButton android:id="@+id/mediaPlayPause"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_centerHorizontal="true" android:background="@android:drawable/ic_media_play" />

<ImageButton android:id="@+id/mediaFwd"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_centerHorizontal="true" android:background="@android:drawable/ic_media_ff" />
</LinearLayout>
<LinearLayout android:id="@+id/bottom_panel2"
android:layout_height="wrap_content" android:layout_width="fill_parent"
android:layout_alignParentBottom="true" android:orientation="horizontal"
android:gravity="center_horizontal|center_vertical">
<TextView android:id="@+id/currentTime"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="" />
<SeekBar android:progress="0" android:secondaryProgress="0"
android:max="1000" android:layout_width="300dip"
android:paddingLeft="15dip" android:paddingRight="15dip"
android:id="@+id/videoProgress" android:layout_height="wrap_content"></SeekBar>

<TextView android:id="@+id/endTime" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="" />

</LinearLayout>


</LinearLayout>

</RelativeLayout>

</FrameLayout>




(2)EnhancedSurfaceView.java

package com.code;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceView;

public class EnhancedSurfaceView

extends SurfaceView {
TapListener listener;

public EnhancedSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
gestureListener.onSingleTapUp(event);
}

return (true);
}

public void addTapListener(TapListener l) {
listener = l;
}

public void removeTapListener(TapListener l) {
listener = null;
}

private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {

listener.onTap(e);

return (true);
}
};

public interface TapListener {
void onTap(MotionEvent event);
}
}




(3)VideoPlayerFragment.java


package com.code;

import java.io.IOException;
import java.util.Formatter;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import com.code.R;

import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.Toast;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

public class VideoPlayerFragment extends Fragment implements
MediaPlayer.OnBufferingUpdateListener,
MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener,
MediaPlayer.OnVideoSizeChangedListener, SurfaceHolder.Callback,
MediaPlayer.OnErrorListener {

private int videoWidth;
private int videoHeight;
private MediaPlayer mediaPlayer;
private SurfaceHolder holder;
private Uri mediaUri;
private boolean isVideoSizeKnown = false;
private boolean isVideoReadyToBePlayed = false;
private PowerManager.WakeLock screenWakeLock;
private int bufferedPercent = 0;
private ScheduledFuture<?> finisherFuture;
private boolean wasPaused = false;
private View topPanel = null;
private View bottomPanel = null;
private ImageButton mediaPlayPause = null;
private ImageButton mediaRew = null;
private ImageButton mediaFwd = null;
private long lastActionTime = 0L;
EnhancedSurfaceView preview;
ProgressBar progress = null;
ProgressBar videoProgress = null;
TextView currentTime = null;
TextView endTime = null;
private static final int SHOW_PROGRESS = 2;
private boolean mDragging;

StringBuilder mFormatBuilder;
Formatter mFormatter;
private boolean DEBUG = DirectvApplication.showLogs();
//private boolean onStopCalled=false;
//private int currentPlayerDuration;


public VideoPlayerFragment() {
DEBUG = DirectvApplication.showLogs();
}

// Activity has to call this api to set required field to play video.
public void setVideoInformation(Uri uri, String videoCaption) {

updateCaption(videoCaption);
mediaUri = uri;

}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
DEBUG = DirectvApplication.showLogs();

// getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
PowerManager pm = (PowerManager) getActivity().getSystemService(
Context.POWER_SERVICE);
screenWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"Video Player");
screenWakeLock.acquire();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub

return inflater.inflate(R.layout.custom_video, container, false);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);

preview = (EnhancedSurfaceView) getView().findViewById(
R.id.video_player_surface);
preview.addTapListener(onTap);

holder = preview.getHolder();
progress = (ProgressBar) getView().findViewById(R.id.progress1);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
topPanel = getView().findViewById(R.id.top_panel);
bottomPanel = getView().findViewById(R.id.bottom_panel);
// new code
mediaPlayPause = (ImageButton) getView().findViewById(
R.id.mediaPlayPause);
mediaPlayPause.setOnClickListener(onMedia);

mediaFwd = (ImageButton) getView().findViewById(R.id.mediaFwd);
mediaFwd.setOnClickListener(onMedia);

mediaRew = (ImageButton) getView().findViewById(R.id.mediaRew);
mediaRew.setOnClickListener(onMedia);

// New Code
videoProgress = (ProgressBar) getView()
.findViewById(R.id.videoProgress);

if (videoProgress != null) {
if (videoProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) videoProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
}
endTime = (TextView) getView().findViewById(R.id.endTime);
currentTime = (TextView) getView().findViewById(R.id.currentTime);

disableMediaButtons();// new code

// mediaUrl = "http://jsharkey.org/downloads/dailytest.3gp";
lastActionTime = SystemClock.elapsedRealtime();
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());

topPanel.setVisibility(View.GONE);
bottomPanel.setVisibility(View.GONE);

}

@Override
public void onStart() {
super.onStart();

preview.postDelayed(onEverySecond, 1000);
}

@Override
public void onResume() {
super.onResume();
DEBUG = DirectvApplication.showLogs();
if (wasPaused) {
// finish();
}
preview.postDelayed(onEverySecond, 1000);
// setupTimer();
}

@Override
public void onPause() {
// releaseScreenLock();
super.onPause();
// releaseMediaPlayer();
// doCleanUp();
// if (finisherFuture != null) {
// finisherFuture.cancel(true);
// }
// wasPaused = true;
// stopTimer();
}

@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();

//onStopCalled=true;
//Log.d("Test", "On Stop is called....");
}

@Override
public void onDestroy() {
super.onDestroy();

releaseScreenLock();
releaseMediaPlayer();
doCleanUp();
if (finisherFuture != null) {
finisherFuture.cancel(true);
}
// stopTimer();
}

private void updateCaption(String caption) {
TextView captionTextView = (TextView) getView().findViewById(
R.id.video_player_caption);
captionTextView.setText(caption);
}

private void playVideo() {
doCleanUp();
progress.setVisibility(View.VISIBLE);
scheduleVideoPlaybackAborter();

try {

if(mediaPlayer!=null){
mediaPlayer.release();
}

mediaPlayer = new MediaPlayer();

// mediaPlayer.setDataSource(mediaUrl);
mediaPlayer.setDataSource(getActivity(), mediaUri);
mediaPlayer.setDisplay(holder);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnVideoSizeChangedListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//Log.d("Test", " VideoPlayerActivity - done preparing");
mediaPlayer.prepareAsync();

//Log.d("Test","------------------ VideoPlayerActivity - done preparing");
} catch (IOException e) {

showErrorDialogAndFinishActivity("Network error");
}
}

private void showErrorDialogAndFinishActivity(String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

builder.setTitle("Exception!").setMessage(message)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
getActivity().finish();
}
}).show();
}

private void scheduleVideoPlaybackAborter() {
if (finisherFuture != null) {
finisherFuture.cancel(true);
}

Runnable aborter = new Runnable() {
public void run() {

if (bufferedPercent == 0) {
showErrorDialogAndFinishActivity("Network Error");
}
}
};

finisherFuture = Executors.newSingleThreadScheduledExecutor().schedule(
aborter, 30, TimeUnit.SECONDS);
}

public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (width == 0 || height == 0) {
return;
}
isVideoSizeKnown = true;
videoWidth = width;
videoHeight = height;
if (isVideoReadyToBePlayed && isVideoSizeKnown) {
startVideoPlayback();
}
}

public void onPrepared(MediaPlayer mediaplayer) {

isVideoReadyToBePlayed = true;
progress.setVisibility(View.GONE);
if (isVideoReadyToBePlayed && isVideoSizeKnown) {
startVideoPlayback();
}
}

public void surfaceCreated(SurfaceHolder holder) {

// Log.d("Test", "Surface is created.....");

playVideo();
}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// No implementation
}

public void surfaceDestroyed(SurfaceHolder holder) {

// No implementation
mediaPlayer.pause();
//Log.d("Test", "Surface is destroyed.........");
}

private void releaseScreenLock() {
if (screenWakeLock.isHeld()) {
screenWakeLock.release();
}
}

private void releaseMediaPlayer() {

//Log.d("Test", "Release playerr is called...");
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;

}
}

private void doCleanUp() {
videoWidth = 0;
videoHeight = 0;
isVideoReadyToBePlayed = false;
isVideoSizeKnown = false;
}

private void startVideoPlayback() {
holder.setFixedSize(videoWidth, videoHeight);

// if(onStopCalled){
//
// }
mediaPlayer.start();
enableMediaButtons();// new code
setPauseIcon();// new code
mHandler.sendEmptyMessage(SHOW_PROGRESS);// new code

}

public void onCompletion(MediaPlayer mp) {
setPlayIcon();

Toast.makeText(getActivity(),
"\nThis program has ended. Thanks for watching.\n",
Toast.LENGTH_SHORT).show();
getActivity().finish();
}

public void onBufferingUpdate(MediaPlayer mp, int percent) {

bufferedPercent = percent;

}

public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub

//Log.d("Test", "---------Some error---------------");
showErrorDialogAndFinishActivity("Unable to play video.");
return true;
}

private EnhancedSurfaceView.TapListener onTap = new EnhancedSurfaceView.TapListener() {
public void onTap(MotionEvent event) {

showPanels();
setProgress();

}
};

private void showPanels() {

if (progress.getVisibility() == View.GONE) {
lastActionTime = SystemClock.elapsedRealtime();
topPanel.setVisibility(View.VISIBLE);
bottomPanel.setVisibility(View.VISIBLE);
mHandler.sendEmptyMessage(SHOW_PROGRESS);
}

}

private void clearPanels() {
lastActionTime = 0;
topPanel.setVisibility(View.GONE);
bottomPanel.setVisibility(View.GONE);

}

private Runnable onEverySecond = new Runnable() {
public void run() {
if (lastActionTime > 0
&& SystemClock.elapsedRealtime() - lastActionTime > 5000) {
clearPanels();
}
preview.postDelayed(onEverySecond, 1000);

}
};

// new code
private View.OnClickListener onMedia = new View.OnClickListener() {
public void onClick(View v) {

switch (v.getId()) {

case R.id.mediaPlayPause:

if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
setPlayIcon();
setProgress();

} else {

mediaPlayer.start();
setPauseIcon();
setProgress();
mHandler.sendEmptyMessage(SHOW_PROGRESS);

}

break;

case R.id.mediaFwd:

int posFwd = mediaPlayer.getCurrentPosition();
posFwd += 5000; // milliseconds
mediaPlayer.seekTo(posFwd);
setProgress();

break;

case R.id.mediaRew:

int posRew = mediaPlayer.getCurrentPosition();
posRew -= 5000; // milliseconds
mediaPlayer.seekTo(posRew);
setProgress();

break;

}

}
};

private void setPlayIcon() {
mediaPlayPause.setBackgroundResource(android.R.drawable.ic_media_play);
}

private void setPauseIcon() {
mediaPlayPause.setBackgroundResource(android.R.drawable.ic_media_pause);
}

private void disableMediaButtons() {
mediaPlayPause.setClickable(false);
mediaFwd.setClickable(false);
mediaRew.setClickable(false);
}

private void enableMediaButtons() {
mediaPlayPause.setClickable(true);
mediaFwd.setClickable(true);
mediaRew.setClickable(true);
}

private String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;

int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;

mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds)
.toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}

private int setProgress() {

if (progress.getVisibility() == View.GONE) {
if (mediaPlayer == null || mDragging) {
return 0;
}

if (mediaPlayer == null) {
return 0;
}
//Log.d("Test","Media Player "+mediaPlayer);
int position = mediaPlayer.getCurrentPosition();
int duration = mediaPlayer.getDuration();
if (videoProgress != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
// pos=1000;

videoProgress.setProgress((int) pos);

}
int percent = bufferedPercent;
videoProgress.setSecondaryProgress(percent * 10);
}

if (endTime != null)
endTime.setText(stringForTime(duration));
if (currentTime != null)
currentTime.setText(stringForTime(position));

return position;

} else {
return 0;
}
}

private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int pos;
switch (msg.what) {

case SHOW_PROGRESS:
pos = setProgress();
if (!mDragging
&& (mediaPlayer != null && mediaPlayer.isPlaying())) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
}
break;
}
}
};

private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
long duration;

public void onStartTrackingTouch(SeekBar bar) {
showPanels();
setProgress();
if (mediaPlayer != null) {
duration = mediaPlayer.getDuration();
}
}



public void onProgressChanged(SeekBar bar, int progress,
boolean fromtouch) {


if (fromtouch) {
mDragging = true;

if (mediaPlayer != null) {
duration = mediaPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mediaPlayer.seekTo((int) newposition);
if (currentTime != null)
currentTime.setText(stringForTime((int) newposition));

}
}
}

public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
// updatePausePlay();
showPanels();
setProgress();
}
};

}

5 comments:

  1. thanks for writing this ...
    if u dont mind could u please send the source code so that i can directly use at irshad@esolzmail.com
    please....

    ReplyDelete
  2. Ahmad,

    You have everything required to use this
    custom controller.

    Just create on activity and add the above fragment
    in the activity layout.

    From your activity,just call the fragment api

    // Activity has to call this api to set required
    field to play video.
    public void setVideoInformation(Uri uri, String videoCaption) {

    updateCaption(videoCaption);
    mediaUri = uri;

    }

    ReplyDelete
  3. i got error in DirectvApplicationDiewctive

    plz help

    ReplyDelete
    Replies
    1. What is the error? Please give more detail

      Delete
    2. Cannot resolve DirectvApplication. It's because the import does not exist for "import com.code.DirectvApplication;"

      Delete