I want to play a video in full screen in a videoview and after some time I want to crop to a circular view?
How can I achieve that ?
There is a better way.
You can create a custom SurfaceView. Which actually clips the view in circular shape. And from this custom view you can set display to MediaPlayer object.
public class VideoSurfaceView extends SurfaceView {
private final static String TAG = "VideoSurfaceView";
private Path clipPath;
private boolean isCircular;
public VideoSurfaceView(Context context) {
super(context);
init();
}
public VideoSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public VideoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
clipPath = new Path();
}
#Override
protected void dispatchDraw(Canvas canvas) {
if (this.isCircular)
canvas.clipPath(clipPath);
super.dispatchDraw(canvas);
}
/**
* Crops the view in circular shape
* #param centerX
* #param centerY
* #param radius
*/
public void cropCircle(float centerX, float centerY, int radius) {
Log.i(TAG, "cropCircle: x=" + centerX + " ,y= " + centerY + ", radius=" + radius);
clipPath.addCircle(centerX, centerY, radius, Path.Direction.CW);
}
/**
* Sets the flag for cropping the view in circular shape
* #param isCircular
*/
public void setCircular(boolean isCircular) {
this.isCircular = isCircular;
invalidate();
}
}
In your activity you can implement SurfaceHolder.Callback & set MediaPlayer's display in overridden method.
public class MainActivity extends AppCompatActivity implements MediaPlayer.OnCompletionListener, SurfaceHolder.Callback {
private final static String TAG = "MainActivity";
#BindView(R.id.activity_main_video_surface_view)
protected VideoSurfaceView videoView;
private Handler handler;
private boolean inCircleMode;
private final static int CIRCULAR_INTERVAL = 5000;
private final static int MINIMUM_CARD_HEIGHT = 300;
private final static int MAXIMUM_CARD_HEIGHT = 500;
//Parameters for video view.
private int cropCenterX;
private int cropCenterY;
private int cropRadius;
private int croppedLayoutWidth;
private int croppedLayoutHeight;
private int fullLayoutWidth;
private int fullLayoutHeight;
private MediaPlayer player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initParameters();
}
/**
* Initialise the parameters used.
*/
private void initParameters() {
SurfaceHolder holder = videoView.getHolder();
holder.addCallback(this);
player = MediaPlayer.create(this, R.raw.bird_s);
player.setOnCompletionListener(this);
//Setting the video with proper aspect ratio.
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
int dimenFull[] = Utility.getVideoDimensions(player, width, height);
fullLayoutWidth = dimenFull[0];
fullLayoutHeight = dimenFull[1];
setVideoLayout();
}
//Runnable for switching the views from circular video to full screen video.
private Runnable runnable = new Runnable() {
#Override
public void run() {
inCircleMode = !inCircleMode;
setVideoLayout();
handler.postDelayed(runnable, CIRCULAR_INTERVAL);
}
};
/**
* Calculates the dimensions required for cropped video view.
*/
private void calculateCroppedParams() {
int dimen[] = Utility.getVideoDimensions(player, 100, 100);
croppedLayoutWidth = dimen[0];
croppedLayoutHeight = dimen[1];
cropRadius = croppedLayoutWidth / 2;
cropCenterX = cropRadius;
cropCenterY = cropRadius;
}
/**
* Change the layout dimensions for video view.
*/
private void setVideoLayout() {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) videoView.getLayoutParams();
//Changing the margin, width & height of videoView.
layoutParams.setMargins(0, inCircleMode ? cardView.getVideoMargin() : 0, 0, 0);
layoutParams.width = inCircleMode ? croppedLayoutWidth : fullLayoutWidth;
layoutParams.height = inCircleMode ? croppedLayoutHeight : fullLayoutHeight;
layoutParams.addRule(inCircleMode ? RelativeLayout.CENTER_HORIZONTAL : RelativeLayout.CENTER_IN_PARENT);
videoView.cropCircle(cropCenterX, cropCenterY, cropRadius);
videoView.setCircular(inCircleMode);
videoView.setLayoutParams(layoutParams);
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
}
#Override
public void onLayout() {
Log.i(TAG, "onLayout: starting runnable");
calculateCroppedParams();
player.start();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
player.setDisplay(surfaceHolder);
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
#Override
protected void onStop() {
Log.i(TAG, "onStop");
super.onStop();
}
#Override
protected void onRestart() {
super.onRestart();
}
#Override
protected void onPause() {
super.onPause();
if (player != null && player.isPlaying())
player.pause();
}
#Override
protected void onResume() {
super.onResume();
if (player != null && !player.isPlaying())
player.start();
}
}
For more details on how to crop the video in different shapes, please check my blog post VideoInShapes.
Another way is put this type of image overlay on your videoview Relative or FrameLayout (Circuler is transprent so videoview will visible only in circle)
By default make visibility GONE this imageView and Change VISIBLE it runtime when you want.
Related
I am using the WallpaperService class to set a live wallpaper on the device.
I want to implement security on the system screen (to prevent screenshot or recording) where the 'Set Wallpaper' button shows up by the android system.
So far, I have found one method of SurfaceView class - surfaceview.setSecure(boolean value)
But, I am not able to get the instance of the SurfaceView inside my class.
Please suggest some workaround to get the instance of this class.
My Code-
public class LiveWallpaperService extends WallpaperService {
private int mDeviceWidth, mDeviceHeight;
private int mAnimationWidth, mAnimationHeight;
#Override
public Engine onCreateEngine() {
Movie movie = null;
// Some Code here
return new GIFWallpaperEngine(movie);
}
private class GIFWallpaperEngine extends Engine {
private final int frameDuration = 24;
private SurfaceHolder holder;
private final Movie movie;
private boolean visible;
private final Handler handler;
private final Runnable drawGIF = new Runnable() {
public void run() {
draw();
}
};
public SurfaceView getSurfaceView(){
// How to find the SurfaceView object here?
}
GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
mDeviceWidth = width;
mDeviceHeight = height;
}
private void draw() {
if (movie != null) {
try {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
final float scaleFactorX = mDeviceWidth / (mAnimationWidth * 1.f); //608 is image width
final float scaleFactorY = mDeviceHeight / (mAnimationHeight * 1.f);
// Adjust size and position to fit animation on the screen
canvas.scale(scaleFactorX, scaleFactorY); // w,h Size of displaying Item
movie.draw(canvas, 0, 0); // position on x,y
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
I'm trying to make a media controller in Android studio but using a fragment instead of an activity, I'm using the code below, but it gives me the following error :
public class Tab1Helloworld extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab1helloworld, container, false);
return rootView;
VideoView video = (VideoView)rootView.findViewById(R.id.videoView);
video.requestFocus();
String videopath = "android.resource://com.r.teamkape.kiddiecodiel/" + R.raw.helloworldvid;
video.setVideoURI(Uri.parse(videopath));
video.setMediaController(new MediaController(this)); //error in (this)[enter image description here][1]
video.requestFocus();
video.start();
}
}
public class Tab1Helloworld extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{ View rootView = inflater.inflate(R.layout.tab1helloworld,container, false);
VideoView video = (VideoView)rootView.findViewById(R.id.videoView);
video.requestFocus();
String videopath = "android.resource://com.r.teamkape.kiddiecodiel/" + R.raw.helloworldvid;
video.setVideoURI(Uri.parse(videopath));
video.setMediaController(new MediaController(getActivity())); //error in (this)[enter image description here][1]
video.requestFocus();
video.start();
return rootView;
}
}
#xhen, Use below code this works perfect,
in xml layout add this
<sg.xyz.test.util.CustomVideoView
android:id="#+id/videoview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
/>
in your Fragment class call these medthods
private MediaController mediaController;
private Uri uri;
public void setupVideo(){
if (mediaController == null) {
mediaController = new
MediaController(mContext);
mediaController.setAnchorView(mBinding.videoview);
mBinding.videoview.setMediaController(mediaController);
}
try {
uri = Util.buildURiPath(resourceID);
mBinding.videoview.setVideoURI(uri);
} catch (Exception e) {
Logger.debug("Error: " + e.getMessage());
e.printStackTrace();
}
mBinding.videoview.requestFocus();
mBinding.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mBinding.videoview.start();
mBinding.imageView.setVisibility(View.INVISIBLE);
}
});
mBinding.videoview.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
#Override
public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) {
mediaController.setAnchorView(mBinding.videoview);
}
});
Logger.debug("Duration = " +
mBinding.videoview.getDuration());
}
});
mBinding.videoview.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
AlertDialogFactory.buildAlertDialog(mContext, 0, R.string.video_playing_error).show();
return false;
}
});
}
public static Uri buildURiPath(int resourceID)
{
String uriPath = String.valueOf(Uri.parse("android.resource://" + LoginActivity.PACKAGE_NAME + "/"
+resourceID));
Uri uri = Uri.parse(uriPath);
return uri;
}
Replace this mBinding.videoview with your video object that's it.
Now, Create CustomVideoView class
public class CustomVideoView extends VideoView {
private int width;
private int height;
private Context context;
private VideoSizeChangeListener listener;
private boolean isFullscreen;
public CustomVideoView(Context context) {
super(context);
init(context);
}
public CustomVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* get video screen width and height for calculate size
*
* #param context Context
*/
private void init(Context context) {
this.context = context;
setScreenSize();
}
/**
* calculate real screen size
*/
private void setScreenSize() {
Display display = ((Activity) context).getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= 17) {
//new pleasant way to get real metrics
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
width = realMetrics.widthPixels;
height = realMetrics.heightPixels;
} else if (Build.VERSION.SDK_INT >= 14) {
//reflection for this weird in-between time
try {
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
width = (Integer) mGetRawW.invoke(display);
height = (Integer) mGetRawH.invoke(display);
} catch (Exception e) {
//this may not be 100% accurate, but it's all we've got
width = display.getWidth();
height = display.getHeight();
}
} else {
//This should be close, as lower API devices should not have window navigation bars
width = display.getWidth();
height = display.getHeight();
}
// when landscape w > h, swap it
if (width > height) {
int temp = width;
width = height;
height = temp;
}
}
/**
* set video size change listener
*
*/
public void setVideoSizeChangeListener(VideoSizeChangeListener listener) {
this.listener = listener;
}
public interface VideoSizeChangeListener {
/**
* when landscape
*/
void onFullScreen();
/**
* when portrait
*/
void onNormalSize();
}
#Override
public void setVideoURI(Uri uri) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(this.getContext(), uri);
width = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
height = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
super.setVideoURI(uri);
super.setVideoURI(uri);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// full screen when landscape
setSize(height, width);
if (listener != null) listener.onFullScreen();
isFullscreen = true;
} else {
// height = width * 9/16
setSize(width, width * 9 / 16);
if (listener != null) listener.onNormalSize();
isFullscreen = false;
}
}
/**
* #return true: fullscreen
*/
public boolean isFullscreen() {
return isFullscreen;
}
/**
* set video sie
*
* #param w Width
* #param h Height
*/
private void setSize(int w, int h) {
setMeasuredDimension(w, h);
getHolder().setFixedSize(w, h);
}
}
the issue from the error you added
flag Error:(33, 54) error: incompatible types: Tab1Helloworld cannot be converted to Context
is in this line
replace
video.setMediaController(new MediaController(this));
with
video.setMediaController(new MediaController(getActivity()));
also move
return rootView;
to the end of the method after starting the video
I have the following Live Wallpaper:
public class GLWallpaperVideoDemo extends GLWallpaperService {
public static final String folder = "video";
public static final String TAG = "GLWVD";
public static String videoName="VIDEOWALL.avi";
//video variables
public int videoWidth,videoHeight;
public boolean videoWideScreen=false;
VideoRenderer renderer = null;
public GLWallpaperVideoDemo() {
super();
Log.e(TAG,"constructor()");
}
#Override
public void onCreate() {
Log.e(TAG,"onCreate()");
super.onCreate();
//transfer video to sdcard
Log.d(TAG,"transferring video asset to sdcard");
copyVideoToCard();
Log.d(TAG,"transferred");
//if videoName == blankVideo, then don't load anything
//TODO
NativeCalls.initVideo();
Log.d(TAG,"Opening video");
NativeCalls.loadVideo("file:/"+"sdcard/"
+GLWallpaperVideoDemo.videoName);
//set video dimensions (now that we opened the video)
videoWidth = NativeCalls.getVideoWidth();
videoHeight = NativeCalls.getVideoHeight();
videoWideScreen = ( videoWidth > videoHeight ) ? true : false;
}
private VideoEngine mEngine=null;
#Override
public Engine onCreateEngine() {
Log.e(TAG,"onCreateEngine()");
mEngine = new VideoEngine();
return mEngine;
}
class VideoEngine extends GLEngine {
VideoEngine() {
super();
Log.e(TAG,"VideoEngine VideoEngine()");
if(renderer==null)renderer = new VideoRenderer(GLWallpaperVideoDemo.this,
this);
setRenderer(renderer);
//setRenderMode(RENDERMODE_WHEN_DIRTY);
setRenderMode(RENDERMODE_CONTINUOUSLY);
}
VideoRenderer getRenderer() { return renderer; }
}
}
And this is the renderer:
public class VideoRenderer implements GLWallpaperService.Renderer {
static private String TAG="Renderer>>>>>>>>>>>>";
static boolean runOnce = false;
//MediaPlayer mediaPlayer = MediaPlayer.create(MyApp.getContext(), R.raw.gunfireusedforboardstage);
//screen variables
int screenWidth=50,screenHeight=50;
int drawWidth, drawHeight; //dimensions of fit-to-screen video
int paddingX, paddingY; //padding for fit-to-screen-video
//texture variables
int powWidth,powHeight;
//pointers
GLWallpaperVideoDemo mParent;
GLWallpaperVideoDemo.VideoEngine mParentEngine;
//lock
static public Object lock = new Object();
//fps
long fpsTime;
public int framecount;
public VideoRenderer() {
super();
Log.e(TAG,"Constructor()");
}
public VideoRenderer(GLWallpaperVideoDemo p,
GLWallpaperVideoDemo.VideoEngine e) {
super();
mParent = p;
mParentEngine = e;
Log.e(TAG,"constructor()");
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.e(TAG, "onSurfaceCreated()");
}
void process(int width, int height) {
setScreenDimensions( width, height );
Log.d(TAG,"Killing texture");
NativeCalls.closeOpenGL();
setTextureDimensions( screenWidth, screenHeight );
setFitToScreenDimensions( mParent.videoWidth,
mParent.videoHeight );
if ( !runOnce ) {
Log.e(TAG,"Preparing frame");
NativeCalls.prepareStorageFrame();
}
NativeCalls.initOpenGL();
runOnce = true;
}
//This gets called whenever you preview the wallpaper or set the
//wallpaper
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.e(TAG,"onSurfaceChanged()");
synchronized(lock) {
process(width, height);
}
}
public void onDrawFrame(GL10 gl) {
synchronized(lock) {
//Log.d(TAG,"Drawing ....");
NativeCalls.getFrame(); // from video
NativeCalls.drawFrame(); // using openGL
if(framecount>300)framecount=0;
framecount++;
//Log.e("framecount",Integer.toString(framecount));
if(framecount==117 || framecount==124 ||framecount==137 ||framecount==145||framecount==159||framecount==167)
{new Thread(new Runnable() {
public void run() {
MediaPlayer mp= MediaPlayer.create(MyApp.getContext(), R.raw.gunfireusedforboardstage);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
};
});
}
}).start();}
if (MyDebug.showFPS) {
final float fpsRate;
fpsRate = 1000f/((float) (SystemClock.uptimeMillis()
- fpsTime) );
fpsTime = SystemClock.uptimeMillis();
Log.d(TAG,
TAG+"drawFrame(): fps: "
+String.valueOf(fpsRate)
);
}
}
}
Now you see the variable framecount inside the renderer?
It gets reinitialized every time open the settings of the Wallpaper !!!
The result is that the renderer continues its work, but framecount is set again to 0,
the consequence is that the frames are not in sync with the MediaPlayer anymore.
SOLVED:
I made the variable static :-)
I am trying to code a video player, It play the video well but I can't resize the SurfaceView.
When the MediaPlayer is prepared, I set the size I want and I call requestLayout or forceLayout, but nothing appends. My LogCat say :
08-29 17:42:38.915: I/SEC_Overlay(2707): overlay_setParameter param[4]=0
08-29 17:42:38.915: D/SEC_Overlay(2707): dst width, height have changed [w= 480, h= 800] -> [w=480, h= 800]
08-29 17:42:38.915: I/SEC_Overlay(2707): Nothing to do!
It obviously try to resize but it found that nothing change and doesn't call onMesured or onLayout
My code :
public class VideoSurface extends ViewGroup {
private final String TAG = "VideoSurface";
protected int mWidth = 0 ;
protected int mHeight = 0 ;
protected SurfaceView mSurfaceView;
protected SurfaceHolder mHolder;
public VideoSurface(Context context) {
super(context);
init(context);
}
public VideoSurface(Context context, AttributeSet attrs) {
super(context,attrs);
init(context);
}
public VideoSurface(Context context, AttributeSet attrs, int defStyle) {
super(context,attrs,defStyle);
init(context);
}
private void init(Context context){
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mSurfaceView = new SurfaceView(context);
this.addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder=mSurfaceView.getHolder() ;
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public Surface getSurface(){return mHolder.getSurface();}
public void setSize(Size size){
mWidth = size.width ;
mHeight = size.height ;
}
public void setSize(int w,int h){
mWidth = w ;
mHeight = h ;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
Log.d(TAG,"onMeasure:"+width+"x"+height);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if ((mWidth != 0)&&(mHeight != 0)) {
previewWidth = mWidth;
previewHeight = mHeight;
}
Log.d(TAG,"onLayout L1: Desired:"+mWidth+"x"+mHeight+" Actual:"+previewWidth+"x"+previewHeight);
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
Log.d(TAG,"onLayout L2:"+l+", "+t+", "+r+", "+b);
}
And the herited class :
public class PlayerView extends VideoSurface implements SurfaceHolder.Callback {
private static final String TAG = "PlayerView";
private MediaPlayer mPlayer = new MediaPlayer() ;
private String mVideoPath = "" ;
public PlayerView(Context context) {
super(context);
init();
}
public PlayerView(Context context, AttributeSet attrs) {
super(context,attrs);
init();
}
public PlayerView(Context context, AttributeSet attrs, int defStyle) {
super(context,attrs,defStyle);
init();
}
private void init(){
mHolder.addCallback(this);
mPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener(){
#Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
//TODO
mHolder.setFixedSize(width,height);
setSize(width,height) ;
setLayoutParams(new LayoutParams(width, height));
requestLayout() ;
forceLayout();
Log.d(TAG,"Size:"+width+"x"+height);
}
});
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// TODO
setSize(mPlayer.getVideoWidth(), mPlayer.getVideoHeight());
mPlayer.start();
Log.d(TAG,"Started");
}
});
//TODO DEBUG
mVideoPath = Environment.getExternalStorageDirectory().getPath()+"/external_sd/USB Storage/test.mp4" ;
}
private void prepareVideo(String path){
stop() ;
try {
mPlayer.setDataSource(path) ;
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//TODO
//mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.prepareAsync() ;
}
public void start(String path) {
mVideoPath = path ;
if (!mHolder.isCreating()){
prepareVideo(path) ;
}
}
public void stop() {
if (mPlayer.isPlaying()) {
mPlayer.stop();
}
mPlayer.reset();
}
public void onStop(){
stop() ;
mPlayer.release();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mPlayer.setDisplay(mHolder);
if(!mVideoPath.isEmpty()){
prepareVideo(mVideoPath) ;
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
How can I force the requestLayout() when even forceLayout() doesn't work ?
You can userequestLayout(); to force your layout to redraw so , you need to call
yourLayout.requestLayout(); on your init() .
I'm new in Android and I want to do some animations. I'm trying to make my sprite sheet move automatically. But there is a problem with screen rendering. It leaves a trail while it is moving.Click here to see the screen shot
This is my code:
public class SampleAnimationActivity extends Activity {
/** Called when the activity is first created. */
Screen screen;
MapAnimation mapAnimation;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
screen = new Screen(this);
setContentView(screen);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
}
public class Screen extends SurfaceView implements Callback{
private SurfaceHolder holder;
private MySurfaceViewThread mySurfaceViewThread;
private boolean isSurfaceCreated;
private Bitmap character, tiles;
public Screen(Context context) {
super(context);
initialize();
}
public void initialize(){
//Create a new SurfaceHolder and assign this class as its callback...
holder = getHolder();
holder.addCallback(this);
isSurfaceCreated = false;
character = BitmapFactory.decodeResource(getResources(),R.drawable.penguin_sprite);
tiles = BitmapFactory.decodeResource(getResources(), R.drawable.tile_sprites);
resume();
}
public void resume(){
//Create and start the graphics update thread.
if(mySurfaceViewThread == null){
mySurfaceViewThread = new MySurfaceViewThread();
if(isSurfaceCreated == true){
mySurfaceViewThread.start();
}
}
}
public void pause(){
//Kill the graphics update thread
if(mySurfaceViewThread != null){
mySurfaceViewThread.pause();
mySurfaceViewThread = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
isSurfaceCreated = true;
if(mySurfaceViewThread != null){
mySurfaceViewThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
isSurfaceCreated = false;
pause();
}
public class MySurfaceViewThread extends Thread{
private boolean isPaused;
private boolean characterLoaded, characterDrawn;
private SurfaceHolder surfaceHolder;
public MySurfaceViewThread(){
super();
isPaused = false;
characterLoaded = false;
surfaceHolder = holder;
characterDrawn = false;
}
public void run(){
//Repeat the drawing loop until the thread is stopped
while(!isPaused){
if(!surfaceHolder.getSurface().isValid()){
continue;
}
if(characterLoaded == false){
mapAnimation = new MapAnimation(screen, character);
characterLoaded = true;
}
Canvas canvas = surfaceHolder.lockCanvas();
mapAnimation.onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
public void pause(){
}
public void onDraw(){
}
}
}
}
public class MapAnimation {
private Screen screen;
private Bitmap character;
private int width, height, xPosition, yPosition, xSpeed, ySpeed;
public MapAnimation(Screen screen, Bitmap character) {
this.screen = screen;
this.character = character;
this.width = character.getWidth();
this.height = character.getHeight();
xPosition = 0;
yPosition = 0;
xSpeed = 5;
ySpeed = 5;
}
public void updateCharacter(){
if(xPosition > screen.getWidth() - width - xSpeed){
xSpeed = 0;
ySpeed = 5;
}
if(yPosition > screen.getHeight() - height - ySpeed){
xSpeed = -5;
ySpeed = 0;
}
if(xPosition + xSpeed < 0){
xPosition=0;
xSpeed = 0;
ySpeed = -5;
}
if(yPosition+ySpeed < 0){
yPosition = 0;
xSpeed = 5;
ySpeed = 0;
}
xPosition += xSpeed;
yPosition += ySpeed;
}
public void onDraw(Canvas canvas){
updateCharacter();
Rect src = new Rect(0, 0,135,225);
Rect dst = new Rect(xPosition, yPosition, xPosition+width, yPosition+height);
canvas.drawBitmap(character, src, dst, null);
}
}
Your help will be deeply appreciated :)
I already solved my problem, I just need to add "drawColor(color.BLACk);" before calling mapAnimation.onDraw() method.