Android mediaplayer onSeekComplete not being called - android

I'm writing a media player that will stream live and on demand streams. It's mostly working, but for some reason I can't get seekTo(int) working correctly. My problem is that when I call seekTo(int) I don't get my onSeekComplete callback. I register my callback method in my onPrepared callback.
I should note that I'm also using MediaController and I've registered my MediaPlayer with MediaController. When I seek by taping the seek bar, it goes through my MediaController and I do get my onSeekComplete callback in that scenario. Here's my code.
package com.brockoli.android.hsdroid;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;
import android.widget.MediaController;
import android.widget.MediaController.MediaPlayerControl;
import android.widget.ProgressBar;
public class VideoPlayerActivity extends Activity implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnVideoSizeChangedListener,
SurfaceHolder.Callback,
MediaController.MediaPlayerControl,
OnSeekCompleteListener {
private MediaPlayer mp;
private MediaController mc;
private int width = 0;
private int height = 0;
private SurfaceView surface;
private SurfaceHolder holder;
private ProgressBar timeline = null;
private boolean isPaused = false;
private int mCurrentPosition = 0;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video_player);
if (getLastNonConfigurationInstance() != null) {
mCurrentPosition = (Integer) getLastNonConfigurationInstance();
}
mc = new MediaController(this);
surface = (SurfaceView) findViewById(R.id.surface_video);
holder = surface.getHolder();
holder.addCallback(this);
}
#Override
protected void onPause() {
super.onPause();
isPaused = true;
}
#Override
protected void onResume() {
super.onResume();
width = getScreenWidth();
height = setHeightBasedOnWidth();
isPaused = false;
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mp != null) {
mp.release();
mp = null;
}
}
#Override
public Object onRetainNonConfigurationInstance() {
int currentPosition = 0;
if (mp != null && mp.isPlaying()) {
currentPosition = mp.getCurrentPosition();
}
return currentPosition;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mc.show();
return false;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Intent intent = this.getIntent();
String url = intent.getStringExtra("STREAM_ID");
playVideo(url);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
LayoutParams lp = surface.getLayoutParams();
lp.width = width;
lp.height = height;
surface.setLayoutParams(lp);
if (width != 0 && height != 0) {
holder.setFixedSize(width, height);
mc.setMediaPlayer(this);
mc.setAnchorView(surface);
handler.post(new Runnable() {
#Override
public void run() {
mc.setEnabled(true);
mc.show();
}
});
Log.d("MEDIAPLAYER", "onPrepared start");
mp.seekTo(mCurrentPosition);
//mediaPlayer.start();
}
}
private void playVideo(String url) {
try {
if (mp == null) {
mp = new MediaPlayer();
mp.setScreenOnWhilePlaying(true);
mp.setOnVideoSizeChangedListener(this);
mp.setOnSeekCompleteListener(this);
} else {
mp.stop();
mp.reset();
}
mp.setDataSource(url);
mp.setDisplay(holder);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setOnPreparedListener(this);
mp.prepareAsync();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onVideoSizeChanged(MediaPlayer mediaPlayer, int newWidth, int newHeight) {
/* if (width != 0 && height != 0) {
holder.setFixedSize(width, height);
//mp.seekTo(mCurrentPosition);
Log.d("MEDIAPLAYER", "onVideoSizeChanged start");
//mediaPlayer.start();
}
*/
}
private Point getScreenSize() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
private int getScreenWidth() {
return getScreenSize().x;
}
private int getScreenHeight() {
return getScreenSize().y;
}
private int setHeightBasedOnWidth() {
if (getScreenWidth() > getScreenHeight()) {
return getScreenHeight();
}
return (int) (getScreenWidth()/1.6);
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getBufferPercentage() {
return 0;
}
#Override
public int getCurrentPosition() {
return mp.getCurrentPosition();
}
#Override
public int getDuration() {
return mp.getDuration();
}
#Override
public boolean isPlaying() {
return mp.isPlaying();
}
#Override
public void pause() {
mp.pause();
}
#Override
public void seekTo(int pos) {
mp.seekTo(pos);
}
#Override
public void start() {
Log.d("MEDIAPLAYER", "MediaController start");
mp.start();
}
#Override
public void onSeekComplete(MediaPlayer mp) {
mp.start();
}
}

Devices implement MediaPlayer a little differently sometimes. Check your onInfo listener to see if you're getting feedback.
Edit from comment:
I just tried it myself and it didn't work for me either in my app. The way around it for me was, especially if your media was already playing when the seek event started, if you see the currentPosition increasing again then you know that seeking has been completed.

Related

How to add media controller on VLC android programatically

I want to to add the media controller on VLC player android integration but i didn't find any option to do that i am sharing the code -
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.otherformat);
load = (ProgressBar) this.findViewById(R.id.load);
intent = getIntent();
load.setVisibility(View.VISIBLE);
handler = new Handler();
mFilePath ="http://mm2.pcslab.com/mm/7h800.mp4";
Log.e(TAG, "Playing: " + mFilePath);
mSurface = (SurfaceView) findViewById(R.id.surface);
holder = mSurface.getHolder();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setSize(mVideoWidth, mVideoHeight);
}
#Override
protected void onResume() {
super.onResume();
createPlayer(mFilePath);
}
#Override
protected void onPause() {
super.onPause();
releasePlayer();
}
#Override
protected void onDestroy() {
super.onDestroy();
releasePlayer();
}
/**
* Used to set size for SurfaceView
*
* #param width
* #param height
*/
private void setSize(int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
if (mVideoWidth * mVideoHeight <= 1)
return;
if (holder == null || mSurface == null)
return;
int w = getWindow().getDecorView().getWidth();
int h = getWindow().getDecorView().getHeight();
boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
if (w > h && isPortrait || w < h && !isPortrait) {
int i = w;
w = h;
h = i;
}
float videoAR = (float) mVideoWidth / (float) mVideoHeight;
float screenAR = (float) w / (float) h;
if (screenAR < videoAR)
h = (int) (w / videoAR);
else
w = (int) (h * videoAR);
holder.setFixedSize(mVideoWidth, mVideoHeight);
ViewGroup.LayoutParams lp = mSurface.getLayoutParams();
lp.width = w;
lp.height = h;
mSurface.setLayoutParams(lp);
mSurface.invalidate();
}
/**
* Creates MediaPlayer and plays video
*
* #param media
*/
private void createPlayer(String media) {
releasePlayer();
try {
if (media.length() > 0) {
Toast toast = Toast.makeText(this, media, Toast.LENGTH_LONG);
toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
0);
//toast.show();
}
// Create LibVLC
// TODO: make this more robust, and sync with audio demo
ArrayList<String> options = new ArrayList<String>();
//options.add("--subsdec-encoding <encoding>");
options.add("--aout=opensles");
options.add("--audio-time-stretch"); // time stretching
options.add("-vvv"); // verbosity
libvlc = new LibVLC(this, options);
holder.setKeepScreenOn(true);
// Creating media player
mMediaPlayer = new MediaPlayer(libvlc);
mMediaPlayer.setEventListener(mPlayerListener);
mMediaPlayer.setVideoTrackEnabled(true);
// Seting up video output
final IVLCVout vout = mMediaPlayer.getVLCVout();
vout.setVideoView(mSurface);
//vout.setSubtitlesView(mSurfaceSubtitles);
vout.addCallback(this);
vout.attachViews();
Media m = new Media(libvlc, Uri.parse(media));
mMediaPlayer.setMedia(m);
mMediaPlayer.play();
////////////////////////////////////////////////
/* //mController = new MediaController(this);
mController = (MediaController)findViewById(R.id.mediaController);
mController.setVisibility(View.VISIBLE);
mController.setAnchorView(mSurface);
mController.show(0);*/
/*mController = new MediaController(this);
mController.setAnchorView(mSurface);
handler.post(new Runnable() {
public void run() {
mController.show();
}
});*/
} catch (Exception e) {
Log.e("Err", e.getMessage()+"");
Toast.makeText(this, "Error in creating player!"+e.getMessage(), Toast
.LENGTH_LONG).show();
}
}
private void releasePlayer() {
if (libvlc == null)
return;
mMediaPlayer.stop();
final IVLCVout vout = mMediaPlayer.getVLCVout();
vout.removeCallback(this);
vout.detachViews();
holder = null;
libvlc.release();
libvlc = null;
mVideoWidth = 0;
mVideoHeight = 0;
}
/**
* Registering callbacks
*/
private MediaPlayer.EventListener mPlayerListener = new MyPlayerListener(this);
#Override
public void onNewLayout(IVLCVout vout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) {
if (width * height == 0)
return;
// store video size
mVideoWidth = width;
mVideoHeight = height;
setSize(mVideoWidth, mVideoHeight);
}
#Override
public void onSurfacesCreated(IVLCVout vout) {
}
#Override
public void onSurfacesDestroyed(IVLCVout vout) {
}
#Override
public void onHardwareAccelerationError(IVLCVout vlcVout) {
Log.e(TAG, "Error with hardware acceleration");
this.releasePlayer();
Toast.makeText(this, "Error with hardware acceleration", Toast.LENGTH_LONG).show();
}
private static class MyPlayerListener implements MediaPlayer.EventListener {
private WeakReference<OtherFormat> mOwner;
public MyPlayerListener(OtherFormat owner) {
mOwner = new WeakReference<OtherFormat>(owner);
}
#Override
public void onEvent(MediaPlayer.Event event) {
OtherFormat player = mOwner.get();
switch (event.type) {
case MediaPlayer.Event.EndReached:
Log.d(TAG, "MediaPlayerEndReached");
player.releasePlayer();
break;
case MediaPlayer.Event.Playing:
load.setVisibility(View.GONE);
break;
case MediaPlayer.Event.Paused:
case MediaPlayer.Event.Buffering:
float percent = event.getBuffering(); /* from 0.0f to 100f */
Log.e("Percent><><",""+percent);
break;
case MediaPlayer.Event.Stopped:
default:
break;
}
}
}}
XML for this activity -
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<SurfaceView
android:id="#+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />
<ProgressBar
android:id="#+id/load"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="visible"
android:layout_gravity="center"
/>
<MediaController
android:id="#+id/mediaController"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
</MediaController>
</FrameLayout>
By this code mediacontrollers not showing please help me how to show media controllers for pause, play and seekbar for video position in surfaceview of vlc media player.
I had the same issue and have found a solution.
Sure, it's too late for answer, but maybe I will save some time to someone.
To add default media control you need to implement it in following way
remove MediaController from layout and add some container for media control to to your activity (it will be added programmatically).
<FrameLayout
android:id="#+id/video_surface_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:foregroundGravity="clip_horizontal|clip_vertical"
tools:ignore="true">
<SurfaceView
android:id="#+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />
</FrameLayout>
add controller init to onStart activity or to onCreate
import android.widget.MediaController;
private MediaController controller;
#Override
protected void onStart() {
super.onStart();
....
controller = new MediaController(this);
controller.setMediaPlayer(findViewByid(R.id.video_surface_frame));
controller.setAnchorView(mVideoSurfaceFrame);
mVideoSurfaceFrame.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
controller.show(10000);
}
});
}
to define playerInterface, you need to implement the MediaController.MediaPlayerControl interface like this
private MediaController.MediaPlayerControl playerInterface = new MediaController.MediaPlayerControl() {
public int getBufferPercentage() {
return 0;
}
public int getCurrentPosition() {
float pos = mLibVlc.getPosition();
return (int)(pos * getDuration());
}
public int getDuration() {
return (int)mLibVlc.getLength();
}
public boolean isPlaying() {
return mLibVlc.isPlaying();
}
public void pause() {
mLibVlc.pause();
}
public void seekTo(int pos) {
mLibVlc.setPosition((float)pos / getDuration());
}
public void start() {
mLibVlc.play();
}
public boolean canPause() {
return true;
}
public boolean canSeekBackward() {
return true;
}
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return 0;
}
};
launch your app and tap on video. You will see default media control and it will hide in 10 sec
Good luck!
Link to VideoLan sample on github:
https://code.videolan.org/videolan/vlc-android/blob/f3db2e4a33bf96c03056874322fb5b9304f92259/vlc-android/src/vlc/android/VLC.java
public class Show_Array extends AppCompatActivity implements IVLCVout.Callback {
private TextView container_extension;
private String stream_typee,stream_idd,container_extensionn ;
private String SAMPLE_URL = "";
public int mHeight;
public int mWidth;
private SurfaceView mVideoSurface = null;
private FrameLayout sdk;
private IVLCVout vlcVout;
private LibVLC mLibVlc = null;
private MediaPlayer mMediaPlayer = null;
private int flag = 0;
private ImageButton Resize;
private Media media;
private ArrayList<String> args;
private SurfaceHolder mSurfaceHolderVideo;
private MediaController controller;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.show__array);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
//Referances
Resize = findViewById(R.id.Resize);
mVideoSurface = findViewById(R.id.video_surface);
stream_typee = getIntent().getExtras().getString("stream_type");
stream_idd = getIntent().getExtras().getString("stream_id");
container_extensionn = getIntent().getExtras().getString("container_extension");
args = new ArrayList<>();
args.add("-vvv");
mLibVlc = new LibVLC(this, args);
mMediaPlayer = new MediaPlayer(mLibVlc);
vlcVout = mMediaPlayer.getVLCVout();
sdk = findViewById(R.id.sdk);
Resize_video();
setup_url();
controller = new MediaController(this);
controller.setMediaPlayer(playerInterface);
controller.setAnchorView(mVideoSurface);
mVideoSurface.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
controller.show(10000);
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
mMediaPlayer.release();
mLibVlc.release();
}
void Resize_video()
{
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
mHeight = displayMetrics.heightPixels;
mWidth = displayMetrics.widthPixels;
Resize.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
flag+=1;
int width = 1000;
int height = 560;
if(flag%2!=0) {
LinearLayout.LayoutParams myImageLayout = new LinearLayout.LayoutParams(width, height);
myImageLayout.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
sdk.setLayoutParams(myImageLayout);
vlcVout.setWindowSize(width,height);
}
else
{
LinearLayout.LayoutParams myImageLayout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
myImageLayout.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
sdk.setLayoutParams(myImageLayout);
vlcVout.setWindowSize(mWidth,mHeight);
}
}
});
}
void setup_url()
{
//TextView
container_extension = findViewById(R.id.URL);
if (stream_typee.equals("live"))
{
SAMPLE_URL = "http://uautv.ru:2095/"+stream_typee+"/webserver/6tE#BzW73#sX/"+stream_idd+".ts";
container_extension.setText( SAMPLE_URL);
}else
{
SAMPLE_URL = "http://uautv.ru:2095/"+stream_typee+"/webserver/6tE#BzW73#sX/"+stream_idd+"."+container_extensionn;
container_extension.setText( SAMPLE_URL);
}
}
#Override
protected void onStart() {
super.onStart();
vlcVout.setWindowSize(mWidth,mHeight);
vlcVout.setVideoView(mVideoSurface);
vlcVout.attachViews();
mMediaPlayer.getVLCVout().addCallback(this);
if(!SAMPLE_URL.isEmpty()) {
media = new Media(mLibVlc, Uri.parse(SAMPLE_URL));
mMediaPlayer.setMedia(media);
media.release();
mMediaPlayer.play();
}else
{
Toast.makeText(getApplicationContext(),"URL EMPTY",Toast.LENGTH_LONG).show();
}
}
#Override
protected void onStop() {
super.onStop();
mMediaPlayer.stop();
mMediaPlayer.getVLCVout().detachViews();
mMediaPlayer.getVLCVout().removeCallback(this);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
#Override
public void onNewLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen)
{ }
#Override
public void onSurfacesCreated(IVLCVout vlcVout) {
}
#Override
public void onSurfacesDestroyed(IVLCVout vlcVout) {
}
private MediaController.MediaPlayerControl playerInterface = new MediaController.MediaPlayerControl() {
public int getBufferPercentage() {
return 0;
}
public int getCurrentPosition() {
float pos = mMediaPlayer.getPosition();
return (int)(pos * getDuration());
}
public int getDuration() {
return (int)mMediaPlayer.getLength();
}
public boolean isPlaying() {
return mMediaPlayer.isPlaying();
}
public void pause() {
mMediaPlayer.pause();
}
public void seekTo(int pos) {
mMediaPlayer.setPosition((float)pos / getDuration());
}
public void start() {
mMediaPlayer.play();
}
public boolean canPause() {
return true;
}
public boolean canSeekBackward() {
return true;
}
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return 0;
}
};
}

In Vitamio When I drag the seekBar, the progress bar is inaccurate? How to fix it?

I am using Vitamio Library in my app. But the problem is, while playing when i try to move seek bar forward or backward the progress bar is in accurate.
I debug the code and found that, in setProgress() method in MediaController class:
long position = mPlayer.getCurrentPosition();
this position is always same. I am not getting that why getCurrentPosition() is always returning same value.
I also search it on Vitamio website and i found:
https://www.vitamio.org/en/docs/FAQ/2013/0509/6.html
When I drag the seekBar, Why the progress bar is inaccurate?
It's all right, this isn't Vitamio's bug, because you must drag the seekBar to the key frame, But the key frame is not always on every timestamp, except you use the intra-only encoding.
What does this mean? and how can i fix it. Please help me.
In Vitamio When I drag the seekBar, the progress bar is inaccurate? How to fix it?
I just wanted to tell you all that I had made a custom solution to fix this issue. You can take help from this solution If you still facing this issue. I have made changes in MediaController.java class in library. You just need to replace this class from your previous class and then run your code.
package io.vov.vitamio.widget;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.PopupWindow;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import java.lang.reflect.Method;
import io.vov.vitamio.utils.Log;
import io.vov.vitamio.utils.StringUtils;
public class MediaController extends FrameLayout {
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private MediaPlayerControl mPlayer;
private Context mContext;
private PopupWindow mWindow;
private int mAnimStyle;
private View mAnchor;
private View mRoot;
private SeekBar mProgress;
private TextView mEndTime, mCurrentTime;
private TextView mFileName;
private OutlineTextView mInfoView;
private String mTitle;
private long mDuration;
private boolean mShowing;
private boolean mDragging;
private boolean mInstantSeeking = false;
private boolean mFromXml = false;
private ImageButton mPauseButton;
private AudioManager mAM;
private OnShownListener mShownListener;
private OnHiddenListener mHiddenListener;
private boolean isSeekBar = false; // Change for video time stuck
private boolean isPlayButtonVisible = false; // Change for video time stuck
#SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
long pos;
switch (msg.what) {
case FADE_OUT:
hide();
break;
case SHOW_PROGRESS:
if(!isSeekBar){ // Change for video time stuck
pos = setProgress();
if (!mDragging && mShowing) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
// updatePausePlay(); // Change for video time stuck
}
}
break;
}
}
};
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
if(mPlayer.isPlaying()){ // // Change for video time stuck
isSeekBar = true; // // Change for video time stuck
mDragging = true;
show(3600000);
mHandler.removeMessages(SHOW_PROGRESS);
if (mInstantSeeking)
mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
if (mInfoView != null) {
mInfoView.setText("");
mInfoView.setVisibility(View.VISIBLE);
}
}
}
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (!fromuser)
return;
if(mPlayer.isPlaying()){ // // Change for video time stuck
long newposition = (mDuration * progress) / 1000;
String time = StringUtils.generateTime(newposition);
if (mInstantSeeking)
mPlayer.seekTo(newposition);
if (mInfoView != null)
mInfoView.setText(time);
if (mCurrentTime != null)
mCurrentTime.setText(time);
}
}
public void onStopTrackingTouch(SeekBar bar) {
isSeekBar = false; // // Change for video time stuck
if(mPlayer.isPlaying()){ // // Change for video time stuck
if (!mInstantSeeking)
mPlayer.seekTo((mDuration * bar.getProgress()) / 1000);
if (mInfoView != null) {
mInfoView.setText("");
mInfoView.setVisibility(View.GONE);
}
show(sDefaultTimeout);
mHandler.removeMessages(SHOW_PROGRESS);
mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
mDragging = false;
mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
}
}
};
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mFromXml = true;
initController(context);
}
public MediaController(Context context) {
super(context);
if (!mFromXml && initController(context))
initFloatingWindow();
}
private boolean initController(Context context) {
mContext = context;
mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return true;
}
#Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
}
private void initFloatingWindow() {
mWindow = new PopupWindow(mContext);
mWindow.setFocusable(false);
mWindow.setBackgroundDrawable(null);
mWindow.setOutsideTouchable(true);
mAnimStyle = android.R.style.Animation;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public void setWindowLayoutType() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
try {
mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
Method setWindowLayoutType = PopupWindow.class.getMethod("setWindowLayoutType", new Class[] { int.class });
setWindowLayoutType.invoke(mWindow, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
} catch (Exception e) {
Log.e("setWindowLayoutType", e);
}
}
}
/**
* Set the view that acts as the anchor for the control view. This can for
* example be a VideoView, or your Activity's main view.
*
* #param view The view to which to anchor the controller when it is visible.
*/
public void setAnchorView(View view) {
mAnchor = view;
if (!mFromXml) {
removeAllViews();
mRoot = makeControllerView();
mWindow.setContentView(mRoot);
mWindow.setWidth(LayoutParams.MATCH_PARENT);
mWindow.setHeight(LayoutParams.WRAP_CONTENT);
}
initControllerView(mRoot);
}
/**
* Create the view that holds the widgets that control playback. Derived
* classes can override this to create their own.
*
* #return The controller view.
*/
protected View makeControllerView() {
return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(getResources().getIdentifier("mediacontroller", "layout", mContext.getPackageName()), this);
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v.findViewById(getResources().getIdentifier("mediacontroller_play_pause", "id", mContext.getPackageName()));
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mProgress = (SeekBar) v.findViewById(getResources().getIdentifier("mediacontroller_seekbar", "id", mContext.getPackageName()));
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_time_total", "id", mContext.getPackageName()));
mCurrentTime = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_time_current", "id", mContext.getPackageName()));
mFileName = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_file_name", "id", mContext.getPackageName()));
if (mFileName != null)
mFileName.setText(mTitle);
}
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
/**
* Control the action when the seekbar dragged by user
*
* #param seekWhenDragging True the media will seek periodically
*/
public void setInstantSeeking(boolean seekWhenDragging) {
mInstantSeeking = seekWhenDragging;
}
public void show() {
show(sDefaultTimeout);
}
/**
* Set the content of the file_name TextView
*
* #param name
*/
public void setFileName(String name) {
mTitle = name;
if (mFileName != null)
mFileName.setText(mTitle);
}
/**
* Set the View to hold some information when interact with the
* MediaController
*
* #param v
*/
public void setInfoView(OutlineTextView v) {
mInfoView = v;
}
/**
* <p>
* Change the animation style resource for this controller.
* </p>
* <p/>
* <p>
* If the controller is showing, calling this method will take effect only the
* next time the controller is shown.
* </p>
*
* #param animationStyle animation style to use when the controller appears
* and disappears. Set to -1 for the default animation, 0 for no animation, or
* a resource identifier for an explicit animation.
*/
public void setAnimationStyle(int animationStyle) {
mAnimStyle = animationStyle;
}
/**
* Show the controller on screen. It will go away automatically after
* 'timeout' milliseconds of inactivity.
*
* #param timeout The timeout in milliseconds. Use 0 to show the controller
* until hide() is called.
*/
public void show(int timeout) {
if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) {
if (mPauseButton != null)
mPauseButton.requestFocus();
if (mFromXml) {
setVisibility(View.VISIBLE);
} else {
int[] location = new int[2];
mAnchor.getLocationOnScreen(location);
Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
mWindow.setAnimationStyle(mAnimStyle);
setWindowLayoutType();
mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom);
}
mShowing = true;
if (mShownListener != null)
mShownListener.onShown();
}
// updatePausePlay(); // Change for video time stuck
mHandler.sendEmptyMessage(SHOW_PROGRESS);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout);
}
}
public boolean isShowing() {
return mShowing;
}
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
mHandler.removeMessages(SHOW_PROGRESS);
if (mFromXml)
setVisibility(View.GONE);
else
mWindow.dismiss();
} catch (IllegalArgumentException ex) {
Log.d("MediaController already removed");
}
mShowing = false;
if (mHiddenListener != null)
mHiddenListener.onHidden();
}
}
public void setOnShownListener(OnShownListener l) {
mShownListener = l;
}
public void setOnHiddenListener(OnHiddenListener l) {
mHiddenListener = l;
}
private long setProgress() {
if (mPlayer == null || mDragging)
return 0;
long position = mPlayer.getCurrentPosition();
long duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
long pos = 1000L * position / duration;
mProgress.setProgress((int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
mDuration = duration;
if (mEndTime != null)
mEndTime.setText(StringUtils.generateTime(mDuration));
if (mCurrentTime != null)
mCurrentTime.setText(StringUtils.generateTime(position));
return position;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
#Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
if (mPauseButton != null)
mPauseButton.requestFocus();
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private void updatePausePlay() {
if (mRoot == null || mPauseButton == null)
return;
if (mPlayer.isPlaying()){
isPlayButtonVisible = false; // // Change for video time stuck
mPauseButton.setImageResource(getResources().getIdentifier("mediacontroller_pause", "drawable", mContext.getPackageName()));
}else{
isPlayButtonVisible = true; // // Change for video time stuck
mPauseButton.setImageResource(getResources().getIdentifier("mediacontroller_play", "drawable", mContext.getPackageName()));
}
}
private void doPauseResume() {
if (mPlayer.isPlaying())
mPlayer.pause();
else
mPlayer.start();
updatePausePlay();
}
#Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null)
mPauseButton.setEnabled(enabled);
if (mProgress != null)
mProgress.setEnabled(enabled);
super.setEnabled(enabled);
}
public interface OnShownListener {
public void onShown();
}
public interface OnHiddenListener {
public void onHidden();
}
public interface MediaPlayerControl {
void start();
void pause();
long getDuration();
long getCurrentPosition();
void seekTo(long pos);
boolean isPlaying();
int getBufferPercentage();
}
}

SurfaceView not working inside PopupWindow

I gonna show a preview using a PopupWindow based on AirView feature of Samsung SPen
But the problem is that the SurfaceView is not created and non of the SurfaceHolder.Callback methods are called.
The surface region becomes transparent when the popup is displayed because the surface is not created at all.
SurfaceView is not created and is transparent:
HoverPreview:
public class HoverPreview extends LinearLayout implements View.OnHoverListener, SurfaceHolder.Callback {
private static final String TAG = "HoverPreview";
private SurfaceHolder mHolder = null;
View mAnchorView = null;
String videoPath;
int position;
private boolean IsMediaPlayerReady = false;
private MediaPlayer mMediaPlayer;
private SurfaceView mSurfaceView;
Context context;
public HoverPreview(Context context, String videoPath, int position) {
super(context);
this.videoPath = videoPath;
this.position = position;
setupLayout(context);
}
public HoverPreview(Context context, AttributeSet attrs) {
super(context, attrs);
setupLayout(context);
}
public HoverPreview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setupLayout(context);
}
private void setupLayout(Context context) {
this.context = context;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.media_browser_hover, this);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "HoverSurface created");
final Surface surface = surfaceHolder.getSurface();
if (surface == null) return;
if (!surface.isValid()) return;
mHolder = surfaceHolder;
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(videoPath);
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.setDisplay(mHolder);
mAnchorView.setTag(mMediaPlayer);
mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
#Override
public void onVideoSizeChanged(MediaPlayer mediaPlayer, int i, int i2) {
mHolder.setFixedSize(i, i2);
}
});
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
Log.d(TAG, "MediaPlayer preview is prepared");
IsMediaPlayerReady = true;
if (mMediaPlayer != null && IsMediaPlayerReady) {
if (position > 0)
mMediaPlayer.seekTo(position);
mMediaPlayer.start();
}
}
});
Log.d(TAG, "MediaPlayer is created");
try {
mMediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
Log.d(TAG, "HoverSurface changed");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "HoverSurface destroyed");
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
//thumbnailImageView.setTag(null);
}
}
public void setAnchorView(View view) {
mAnchorView = view;
}
#Override
public boolean onHover(View view, MotionEvent motionEvent) {
try {
if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
Log.d(TAG, "ACTION_HOVER_ENTER");
mSurfaceView = (SurfaceView) findViewById(R.id.media_browser_hoverSurfaceView);
mHolder = mSurfaceView.getHolder();
if (mHolder != null) {
mHolder.addCallback(this);
}
} else if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
Log.d(TAG, "ACTION_HOVER_EXIT");
if (mAnchorView.getTag() != null) {
MediaPlayer mMediaPlayer = (MediaPlayer) mAnchorView.getTag();
mMediaPlayer.stop();
mMediaPlayer.release();
mAnchorView.setTag(null);
}
}
} catch (Exception e) {
Log.e(TAG, e.getMessage() + Utils.toString(e.getStackTrace()));
}
return false;
}
}
The code to show the preview:
final PopupWindow popupWindow = new PopupWindow(context);
final HoverPreview hoverPreview = new HoverPreview(context, videoPath, 0);
hoverPreview.setAnchorView(thumbnailImageView);
thumbnailImageView.setOnHoverListener(new View.OnHoverListener() {
#Override
public boolean onHover(View view, MotionEvent motionEvent) {
hoverPreview.onHover(view, motionEvent);
if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
popupWindow.setContentView(hoverPreview);
popupWindow.setWidth(600);
popupWindow.setHeight(400);
popupWindow.showAtLocation(thumbnailImageView, ToolHoverPopup.Gravity.NO_GRAVITY, 10, 10);
Log.d(TAG, "Manual Hover Enter");
} else if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
Log.d(TAG, "Manual Hover Exit");
if (popupWindow != null)
popupWindow.dismiss();
}
return true;
});
Here's my complete working solution:
I borrowed some code from ToolHoverPopup class from SPen library, also I customized for this special popup so that nothing is created or inflated until the actual hovering is happened so that we don't consume resources for enabling such a preview in lists.
We need to have our preview attached to a Window so because of this we have to manage all the underlying job of positioning which is normally done by PopupWindow, so I completely removed the dependency on the PopupWindow and now my HoverPreview class is fully working and manages all the jobs, also it has the ability to determine the Hover Detection delay in milliseconds.
Screenshot (SurfaceView is created)
Usage: (Since the layout contains SurfaceView and is resource intensive, I manually trigger onHover event so that the real surface creation is performed only when the real hover is performed. Also by this, I don't create any object of HoverPreview before it's needed)
thumbnailImageView.setOnHoverListener(new View.OnHoverListener() {
#Override
public boolean onHover(View view, MotionEvent motionEvent) {
HoverPreview hoverPreview;
if (thumbnailImageView.getTag() == null) {
hoverPreview = new HoverPreview(context, getActivity().getWindow(), videoPath, 0);
hoverPreview.setHoverDetectTime(1000);
thumbnailImageView.setTag(hoverPreview);
} else
hoverPreview = (HoverPreview) thumbnailImageView.getTag();
hoverPreview.onHover(null, motionEvent);
if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT)
thumbnailImageView.setTag(null);
return true;
}
});
HoverPreview:
public class HoverPreview extends LinearLayout implements View.OnHoverListener, SurfaceHolder.Callback {
private static final int MSG_SHOW_POPUP = 1;
private static final int MSG_DISMISS_POPUP = 2;
private static final int HOVER_DETECT_TIME_MS = 300;
private static final int POPUP_TIMEOUT_MS = 60 * 1000;
protected int mHoverDetectTimeMS;
private static final String TAG = "HoverPreview";
private SurfaceHolder mHolder = null;
String videoPath;
int position;
private boolean IsMediaPlayerReady = false;
private MediaPlayer mMediaPlayer;
private SurfaceView mSurfaceView;
Context context;
private HoverPopupHandler mHandler;
Window window;
public HoverPreview(Context context, Window window, String videoPath, int position) {
super(context);
this.mHoverDetectTimeMS = HOVER_DETECT_TIME_MS;
this.videoPath = videoPath;
this.position = position;
this.window = window;
setupLayout(context);
}
private void setupLayout(Context context) {
this.context = context;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rootView = inflater.inflate(R.layout.media_browser_hover, this);
mSurfaceView = (SurfaceView) findViewById(R.id.media_browser_hoverSurfaceView);
}
View rootView;
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "HoverSurface created");
final Surface surface = surfaceHolder.getSurface();
if (surface == null) return;
if (!surface.isValid()) return;
mHolder = surfaceHolder;
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(videoPath);
} catch (IOException e) {
e.printStackTrace();
return;
}
mMediaPlayer.setDisplay(mHolder);
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
Log.d(TAG, "MediaPlayer preview is prepared");
IsMediaPlayerReady = true;
int videoWidth = mMediaPlayer.getVideoWidth();
int videoHeight = mMediaPlayer.getVideoHeight();
Point size = new Point();
int screenHeight = 0;
int screenWidth = 0;
Display display = getDisplay();
display.getSize(size);
screenWidth = size.x - (350 + 30); // margin + padding
screenHeight = size.y;
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSurfaceView.getLayoutParams();
lp.width = screenWidth;
lp.height = (int) (((float) videoHeight / (float) videoWidth) * (float) screenWidth);
mSurfaceView.setLayoutParams(lp);
if (mMediaPlayer != null && IsMediaPlayerReady) {
if (position > 0)
mMediaPlayer.seekTo(position);
mMediaPlayer.start();
findViewById(R.id.media_browser_hoverRootFrameLayout).setVisibility(VISIBLE);
}
}
});
Log.d(TAG, "MediaPlayer is created");
try {
mMediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
Log.d(TAG, "HoverSurface changed");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "HoverSurface destroyed");
try {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
} catch (Exception e) {
}
}
#Override
public boolean onHover(View view, MotionEvent motionEvent) {
try {
if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
Log.d(TAG, "ACTION_HOVER_ENTER");
show(); // checks the timing
} else if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
Log.d(TAG, "ACTION_HOVER_EXIT");
dismiss();
}
} catch (Exception e) {
Log.e(TAG, e.getMessage() + Utils.toString(e.getStackTrace()));
}
return false;
}
/**
* Sets the time that detecting hovering.
*
* #param ms The time, milliseconds
*/
public void setHoverDetectTime(int ms) {
mHoverDetectTimeMS = ms;
}
public void dismiss() {
dismissPopup();
}
private void dismissPopup() {
// remove pending message and dismiss popup
getMyHandler().removeMessages(MSG_SHOW_POPUP);
getMyHandler().removeMessages(MSG_DISMISS_POPUP);
try {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
} catch (Exception e) {
}
if (getParent() != null)
((ViewGroup) getParent()).removeView(this);
}
private Handler getMyHandler() {
if (mHandler == null)
mHandler = new HoverPopupHandler();
return mHandler;
}
public void show() {
// send message to show.
if (getMyHandler().hasMessages(MSG_SHOW_POPUP)) {
return;
// getHandler().removeMessages(MSG_SHOW_POPUP);
}
getMyHandler().sendEmptyMessageDelayed(MSG_SHOW_POPUP, mHoverDetectTimeMS);
}
private void showPopup() {
if (getParent() == null) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER_VERTICAL;
params.x = 350;
window.addContentView(this, params);
}
mHolder = mSurfaceView.getHolder();
if (mHolder != null) {
mHolder.addCallback(this);
}
}
;
private class HoverPopupHandler extends Handler {
#Override
public void handleMessage(Message msg) {
// if (DEBUG)
// android.util.Log.e(TAG, "handleMessage : " + ((msg.what == MSG_SHOW_POPUP) ? "SHOW" : "DISMISS"));
switch (msg.what) {
case MSG_SHOW_POPUP:
showPopup();
sendEmptyMessageDelayed(MSG_DISMISS_POPUP, POPUP_TIMEOUT_MS);
break;
case MSG_DISMISS_POPUP:
dismissPopup();
break;
}
}
}
}

Android MediaPlayer does not display video, only play audio

I have a video file in location /sdcard/abc/a.3gp. Now when I try to play the file in android emulator using the media player that I have just created, I get only the audio, the video is not displayed. The screen remains blank (when it is supposed to play the video).
Here is the media player code that I am using:
package com.example.helloandroid;
import com.example.helloandroid.R;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import android.widget.VideoView;
public class HelloAndroidActivity extends Activity implements
OnBufferingUpdateListener, OnCompletionListener,
OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback {
private static final String TAG = "MediaPlayerDemo";
private int mVideoWidth;
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private SurfaceHolder holder;
private String path;
private Bundle extras;
private static final String MEDIA = "media";
private static final int LOCAL_AUDIO = 1;
private static final int STREAM_AUDIO = 2;
private static final int RESOURCES_AUDIO = 3;
private static final int LOCAL_VIDEO = 4;
private static final int STREAM_VIDEO = 5;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
/**
*
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
mPreview = (SurfaceView) findViewById(R.id.surface_view);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
extras = getIntent().getExtras();
}
private void playVideo() {
doCleanUp();
try {
path = "/sdcard/abc/a.3gp";
if (path == "") {
// Tell the user to provide a media file URL.
Toast
.makeText(
HelloAndroidActivity.this,
"Please edit MediaPlayerDemo_Video Activity, "
+ "and set the path variable to your media file path."
+ " Your media file must be stored on sdcard.",
Toast.LENGTH_LONG).show();
}
// Create a new media player and set the listeners
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(path);
mMediaPlayer.setDisplay(holder);
mMediaPlayer.prepare();
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
catch (Exception e) {
Log.e(TAG, "error: " + e.getMessage(), e);
}
}
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
Log.d(TAG, "onBufferingUpdate percent:" + percent);
}
public void onCompletion(MediaPlayer arg0) {
Log.d(TAG, "onCompletion called");
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
Log.v(TAG, "onVideoSizeChanged called");
if (width == 0 || height == 0) {
Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")");
return;
}
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void onPrepared(MediaPlayer mediaplayer) {
Log.d(TAG, "onPrepared called");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
Log.d(TAG, "surfaceChanged called");
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
Log.d(TAG, "surfaceDestroyed called");
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated called");
playVideo();
}
#Override
protected void onPause() {
super.onPause();
releaseMediaPlayer();
doCleanUp();
}
#Override
protected void onDestroy() {
super.onDestroy();
releaseMediaPlayer();
doCleanUp();
}
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
}
private void doCleanUp() {
mVideoWidth = 0;
mVideoHeight = 0;
mIsVideoReadyToBePlayed = false;
mIsVideoSizeKnown = false;
}
private void startVideoPlayback() {
Log.v(TAG, "startVideoPlayback");
holder.setFixedSize(mVideoWidth, mVideoHeight);
mMediaPlayer.start();
}
}
....................................................................
Layout->main.xml file is:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/home_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<VideoView
android:id="#+id/surface_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</FrameLayout>
............................................................................
I am not sure if the error is in the xml file or in the code.
Moreover in the logs there is no trace of the error.
Please help me out.
Thanks.
Unfortunately, it seems like the one of wide-known Android emulator's disadvantages. It has very limited support of media playing, so video in most cases can't perform well. Even Google engineers advices to use real device and not an emulator to test MediaPlayer-related issues.
use SurfaceView in .xml file instead of VideoView
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/home_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SurfaceView
android:id="#+id/surface_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</FrameLayout>
Let us know once you resolved problem.
Why don't you just use videoview, it's a wrapper of mediaplayer, easy to settup.
P/s: i saw in your code mMediaPlayer.setDisplay(holder); it's nonsense, you should use mMediaPlayer.setDisplay(surfaceHolder); inside surfaceCreated or pass surfaceHolder as a param in playvideo()

Save object Android not working

onRestoreInstanceState(Bundle savedInstanceState)
is not geting called, I am pasting my code below. Actually I want to redraw all the points that are saved when my activity went in background.
package com.geniteam.mytest;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
public class Tutorial2D extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Panel panel = new Panel(this);
outState.putSerializable("test", panel._graphics);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Panel panel = new Panel(this);
panel.set_graphics((ArrayList<GraphicObject>) savedInstanceState.getSerializable("test"));
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private TutorialThread _thread;
private ArrayList<GraphicObject> _graphics = new ArrayList<GraphicObject>();
public ArrayList<GraphicObject> get_graphics() {
return _graphics;
}
public void set_graphics(ArrayList<GraphicObject> graphics) {
_graphics = graphics;
}
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
setFocusable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (_thread.getSurfaceHolder()) {
// if (event.getAction() == MotionEvent.ACTION_DOWN) {
GraphicObject graphic = new GraphicObject(BitmapFactory.decodeResource(getResources(), R.drawable.icon));
graphic.getCoordinates().setX((int) event.getX() - graphic.getGraphic().getWidth() / 2);
graphic.getCoordinates().setY((int) event.getY() - graphic.getGraphic().getHeight() / 2);
_graphics.add(graphic);
//}
return true;
}
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
Bitmap bitmap;
GraphicObject.Coordinates coords;
for (GraphicObject graphic : _graphics) {
bitmap = graphic.getGraphic();
coords = graphic.getCoordinates();
canvas.drawBitmap(bitmap, coords.getX(), coords.getY(), null);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
try{
_thread.setRunning(true);
_thread.start();
}catch(Exception ex){
_thread = new TutorialThread(getHolder(), this);
_thread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
class GraphicObject {
/**
* Contains the coordinates of the graphic.
*/
public class Coordinates {
private int _x = 100;
private int _y = 0;
public int getX() {
return _x + _bitmap.getWidth() / 2;
}
public void setX(int value) {
_x = value - _bitmap.getWidth() / 2;
}
public int getY() {
return _y + _bitmap.getHeight() / 2;
}
public void setY(int value) {
_y = value - _bitmap.getHeight() / 2;
}
public String toString() {
return "Coordinates: (" + _x + "/" + _y + ")";
}
}
private Bitmap _bitmap;
private Coordinates _coordinates;
public GraphicObject(Bitmap bitmap) {
_bitmap = bitmap;
_coordinates = new Coordinates();
}
public Bitmap getGraphic() {
return _bitmap;
}
public Coordinates getCoordinates() {
return _coordinates;
}
}
}
onRestoreInstanceState only gets called if the app is destroyed and re-created. Putting the app in the background then bringing it up again will call onResume, but not onRestoreInstanceState.

Categories

Resources