I'm using a SurfaceView as display to a MediaPlayer, but the video is sideways and I need to rotate it. I tried using SurfaceView.setRotation(90) but this gave me a black View.
If I set the rotation to any degree lower than 90, the video translates to the right (being pushed behind the content of the other page in the ViewPage) by a relative amount.
Here is the code I'm using to create the view and play the video:
final SurfaceView surface = new SurfaceView(getActivity());
surface.setRotation(90);
surface.getHolder().addCallback(new SurfaceHolder.Callback(){
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mPlayer = new MediaPlayer();
mPlayer.setDisplay(surface);
try {
mPlayer.setDataSource(url);
mPlayer.setLooping(true);
mPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
} catch (IOException e) {
e.printStackTrace();
}
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mPlayer.prepareAsync();
mPlayer.setScreenOnWhilePlaying(true);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mPlayer.stop();
mPlayer.release();
}
});
As said, I'm adding the surface to a ViewPage. The video plays, and, aside from rotation, everything else works.
I tried mPlayer.setSurface(holder.getSurface()) with the same results.
I tried using TextureView with limited success. It rotated, but I couldn't scale it and keep aspect ratio with cropping.
Tried locking the canvas and rotating the canvas of the holder, but all I've got was a black View, no matter what degree.
Related
I'm currently working in a custom android native plugin for Capacitor. The plugin consists in an app's footer which is working fine except for a hiding animation.
The problem is I'm changing the WebView margin everytime the footer is being shown/hide, which makes a black(sometimes is orange, probably because is one of app's main colors) bar appears in the space occupied by the footer. Black bar disappears once the animation ends.
I've tried changing the WebView margin at animation start/end and the result is the same.
Thanks in advance guys, here is some code.
Animation XML:
<translate
android:duration="150"
android:fromYDelta="0"
android:toYDelta="100%" />
WebView margin function:
private void changeWebViewMargin(float pixels) {
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) wb.getLayoutParams();
params.setMargins(0, 0, 0, (int) dpTopixel(getContext(), pixels));
wb.setLayoutParams(params);
wb.requestLayout();
}
Hide function:
#PluginMethod()
public void hide(PluginCall call) {
Boolean animated = call.getBoolean("animated");
if (animated == null) {
animated = false;
}
final boolean finalAnimated = animated;
this.getBridge().getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (finalAnimated && footer.getVisibility() == View.VISIBLE) {
changeWebViewMargin(0f);
Animation myAnim = AnimationUtils.loadAnimation(getBridge().getContext(), R.anim.hide_footer);
myAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
footer_img.setVisibility(View.INVISIBLE);
footer.setVisibility(View.INVISIBLE);
btn3.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
footer.startAnimation(myAnim);
footer_img.startAnimation(myAnim);
btn3.startAnimation(myAnim);
} else {
footer_img.setVisibility(View.INVISIBLE);
footer.setVisibility(View.INVISIBLE);
btn3.setVisibility(View.INVISIBLE);
changeWebViewMargin(0f);
}
}
});
}
Instead of working with margins try using WindowInsets:
ViewCompat.setOnApplyWindowInsetsListener(wb, (v, insets) -> {
((ViewGroup.MarginLayoutParams) v.getLayoutParams()).bottomMargin =
insets.getSystemWindowInsetTop() + (int) dpTopixel(getContext(), pixels);
return insets.consumeSystemWindowInsets();
});
Is there any difference in adding single image 10 times and 10 different images(same dimens,same resolution,same file size) one time for animation.?
Because I added 1 image 10 times and provided multiple animation while swiping it was smooth throughout my interaction. but while adding different images (same dimens,same resolution,same file size) for my process, there is severe lag in animating. Some steps i tried to improve performance
1.Adding Layer type and setting null while animation ended (This improves for one time animating, when the animation is continuous, this is not helping)
2.Tried Setting hardwareaccelerated attribute in Manifest
3.Tried setting large heap attribute in manifest
4.Added animation cache for items.
5.Tried running with high RAM devices.
Do we have any options to improve animation performance.?
EDITED:
FrameLayout frame = new FrameLayout(this);
frame.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 700));
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(R.drawable.image1);
arrayList.add(R.drawable.image2);
arrayList.add(R.drawable.image3);
arrayList.add(R.drawable.image4);
arrayList.add(R.drawable.image5);
arrayList.add(R.drawable.image6);
arrayList.add(R.drawable.image7);
arrayList.add(R.drawable.image8);
arrayList.add(R.drawable.image9);
arrayList.add(R.drawable.image10);
arrayList.add(R.drawable.image11);
for(int i=0;i<11;i++){
ImageView imgvw = new ImageView(this);
imgvw.setImageResource(arrayList.get(i));
imgvw.setLayoutParams(new ActionBar.LayoutParams(250, 400));
imgvw.setScaleType(ImageView.ScaleType.FIT_XY);
imgvw.setX(this.getResources().getDisplayMetrics().widthPixels / 2);
imgvw.setRotationY(-45);
imgvw.setScaleY(0.7f);
frame.addView(imgvw);
}
setContentView(frame);
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()){
case MotionEvent.ACTION_DOWN:{
final AnimatorSet animationSet = new AnimatorSet();
for(int i=0;i<frame.getChildCount();i++){
final ImageView vw = (ImageView) frame.getChildAt(i);
// vw.setLayerType(View.LAYER_TYPE_HARDWARE, null);
animationSet.playTogether(
ObjectAnimator.ofFloat(vw, "rotationY", 45),
ObjectAnimator.ofFloat(vw, "scaleY", 0.8f),
ObjectAnimator.ofFloat(vw, "x", 0)
);
animationSet.setDuration(600);
animationSet.setInterpolator(new DecelerateInterpolator(1.5f));
animationSet.start();
animationSet.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
// vw.setLayerType(View.LAYER_TYPE_NONE,null);
animationSet.start();
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
vw.setX(getResources().getDisplayMetrics().widthPixels / 2);
vw.setRotationY(-45);
vw.setScaleY(0.7f);
}
});
}
}
}
Hope you would have added corresponding specific resolution images for different device resolutions.
If using same image in different screen resolutions, those devices with smaller resolutions these kind of lagging may happen.
To generate these images, you should start with your raw resource in vector format and generate the images for each density using the following size scale:
xhdpi: 2.0
hdpi: 1.5
mdpi: 1.0 (baseline)
ldpi: 0.75
More over go through the below suggestions from developer.android wrt screen density
ldpi Resources for low-density (ldpi) screens (~120dpi).
mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
hdpi Resources for high-density (hdpi) screens (~240dpi).
xhdpi Resources for extra-high-density (xhdpi) screens (~320dpi).
xxhdpi Resources for extra-extra-high-density (xxhdpi) screens (~480dpi).
xxxhdpi Resources for extra-extra-extra-high-density (xxxhdpi) uses (~640dpi). Use this for the launcher icon only, see note above.
nodpi Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen's density.
tvdpi Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. This is not considered a "primary" density group. It is mostly intended for televisions and most apps shouldn't need it—providing mdpi and hdpi resources is sufficient for most apps and the system will scale them as appropriate.
If you are adding 10 different images, try using animation list with seperate attributes for each image animation.
By understanding your code in question, I have made some slight alternation such that the reverse animation happens and sequence happens correctly. Hope this helps!!!...
Code inside oncreate method
frame = new FrameLayout(this);
frame.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 700));
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(R.drawable.image1);
arrayList.add(R.drawable.image2);
arrayList.add(R.drawable.image3);
arrayList.add(R.drawable.image4);
arrayList.add(R.drawable.image5);
arrayList.add(R.drawable.image6);
arrayList.add(R.drawable.image7);
arrayList.add(R.drawable.image8);
arrayList.add(R.drawable.image9);
arrayList.add(R.drawable.image10);
//arrayList.add(R.drawable.image11);
for(int i=0;i<arrayList.size();i++){
ImageView imgvw = new ImageView(this);
imgvw.setImageResource(arrayList.get(i));
imgvw.setLayoutParams(new ActionBar.LayoutParams(250, 400));
imgvw.setScaleType(ImageView.ScaleType.FIT_XY);
imgvw.setX(this.getResources().getDisplayMetrics().widthPixels / 2);
imgvw.setRotationY(-45);
imgvw.setScaleY(0.7f);
frame.addView(imgvw);
}
setContentView(frame);
Code for animations:
private int count=0;
private int repeatMode=2;
private int repeatCount=1;
private int duration=300;
private void doAnimation(final FrameLayout frame){
if (count>=frame.getChildCount()){
count=0;
return;
}
ImageView targetView = (ImageView) frame.getChildAt(count++);//frame.getChildCount()-1-count++);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(targetView, "rotationY", 45);
animator1.setRepeatCount(repeatCount);
animator1.setRepeatMode(repeatMode);
animator1.setDuration(duration);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(targetView, "scaleY", 0.8f);
animator2.setRepeatCount(repeatCount);
animator2.setRepeatMode(repeatMode);
animator2.setDuration(duration);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(targetView, "x", 0f);
animator3.setRepeatCount(repeatCount);
animator3.setRepeatMode(repeatMode);
animator3.setDuration(duration);
//sequencial animation
AnimatorSet set = new AnimatorSet();
set.playTogether(animator1, animator2, animator3);
set.start();
set.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
doAnimation(frame);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return onTouchEvent(event);
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
doAnimation(frame);
return true;
}
}
return false;
}
I'm a complete noob . I've managed to write and understand this code after reading this http://developer.android.com/guide/topics/media/camera.html .
But now i want to get the byte array for preview and then convert it to bitmap . But i want to do this in real time without be forced to save a picture file in storage . Please , help!
Here is my program code.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
String TAG = null;
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
mCamera.setDisplayOrientation(90);
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
String TAG = null;
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
private PictureCallback mPicture = new PictureCallback(){
#Override
public void onPictureTaken(byte[] data, Camera camera)
{
// TODO: Implement this method
}
};
}
And main activity :
public class MainActivity extends Activity
{ private Camera mCamera;
private CameraPreview mPreview;
int i;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mCamera = getCameraInstance();
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.frame);
preview.addView(mPreview);
}
public static Camera getCameraInstance()
{
Camera c = null;
try
{
c = Camera.open();}
catch (Exception e)
{ System.out.println("blamjjjh");}
return c;
}
public void releasec(){
mCamera.release();
}
#Override
protected void onStop()
{
super.onStop();
releasec();
}
}
As detailed in the Android Developer docs here (which you might have already read), add an implementation of the PictureCallback interface (see the example below) to your Activity. Also you can use BitmapFactory to then convert the byte array that gets passed back to a Bitmap. Then you can use this as required.
NOTE:
I would also read the docs here on handling Bitmaps efficiently in relation to memory as you might get OutOfMemory errors if you're manipulating Bitmaps.
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//create a Bitmap from the byte array
Bitmap bitmap = BitmapFactory.decodeByteArray(data , 0, data.length);
//use your Bitmap
}
};
You then need to pass this into the takePicture() method against your camera instance e.g.
// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
Hope this helps! :-)
I have a Drawable object in my application which is moving on the screen:
public class MyDrawable extends Drawable {
#Override
public void draw(Canvas canvas) {
// ...
}
// ...
}
It worked fine so far but now I have to animate this Drawable. I checked out the documentation and it looks like that the best option for me is using AnimationDrawable.
I did something like this:
public void addAnimation() {
animation = new AnimationDrawable();
animation.addFrame(resources.getDrawable(R.drawable.anim_0), 100);
animation.addFrame(resources.getDrawable(R.drawable.anim_1), 100);
animation.addFrame(resources.getDrawable(R.drawable.anim_2), 100);
animation.addFrame(resources.getDrawable(R.drawable.anim_3), 100);
animation.setOneShot(false);
refreshAnimationBounds();
animation.start();
}
#Override
public void draw(Canvas canvas) {
refreshAnimationBounds();
animation.draw(canvas);
}
What happens is that my original Drawable is moving as intended but I only see the first frame. What could be the problem?
refreshAnimationBounds(); is just refreshing the bounds of my Drawable object (repositions it).
Edit:
The common:
public void onWindowFocusChanged(boolean hasFocus) {
if (hasFocus) {
animation.start();
} else {
animation.stop();
}
}
solution is not working.
In general Animation package is quite buggy. I recall I had same problem with animation not starting and the solution I came with was to start it not in onCreate() as I formerly did but onWindowFocusChanged() once all view stuff was set. I wasn't extending AnimationDrawable myself but it may be the same origin in your case.
I'm using a Nexus One and the Camera displays horizontal when it should be vertical and vice versa. I've no idea what's wrong. The code works fine on a HTC tattoo. Anyone have any idea what's wrong?
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
Camera mCamera;
Preview(Context context) {
super(context);
// Install a SurfaceHolder.Callback so we get notified when
//the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell
//it where
// to draw.
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the
//preview.
// Because the CameraDevice object is not a shared resource,
//it's very
// important to release it when the activity is paused.
mCamera.stopPreview();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int
w, int h) {
// Now that the size is known, set up the camera parameters
//and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(800, 480);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
Got it working. I added..
parameters.set("orientation", "portrait");
CommonsWare gave me the idea it was that kind of issue thanks man :)