I'm trying to implement a system whereby if an uncaught exception occurs, my exception handler will take a screenshot of the activity, to be saved and sent off as part of a bug report. Is this even possible in Android? I'm passing the activity to the exception handler in the constructor, but every attempt I've used so far to get the screenshot has returned null.
I've tried the following:
Attempt One:
private Bitmap screenshot() {
View view = activity.getWindow().getDecorView(); //also tried getDecorView().getRootView()
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
view.setDrawingCacheEnabled(true);
view.buildDrawingCache(true);
Bitmap image = view.getDrawingCache();
Rect windowbounds = new Rect();
view.getWindowVisibleDisplayFrame(windowbounds);
int width = activity.getWindowManager().getDefaultDisplay().getWidth();
int height = activity.getWindowManager().getDefaultDisplay().getHeight();
Bitmap secondaryBitmap = Bitmap.createBitmap(image, 0, 0, width, height);
view.destroyDrawingCache();
return secondaryBitmap;
}
Attempt Two:
private Bitmap screenshot2()
{
View view = activity.getWindow().getDecorView(); //also tried getDecorView().getRootView()
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Bitmap viewBmp = Bitmap.createBitmap(view.getWidth(),view.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(viewBmp);
view.draw(canvas);
return viewBmp;
}
In attempt #1 the view.getDrawingCache() returns null, and in attempt #2 Bitmap.createBitmap returns null.
Any Android developers have any idea on how to take a screenshot in the UncaughtExceptionHandler?
You do not want:
Bitmap viewBmp = Bitmap.createBitmap(view.getLayoutParams().width, view.getLayoutParams().height,
Bitmap.Config.ARGB_8888);
The LayoutParams does not normally have the actual width and height. Often it has negative values, indicating wrap_content or match_parent.
Instead, try:
Bitmap viewBmp = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
Bitmap.Config.ARGB_8888);
or something along those lines. You want the actual width and height of the container, not the width and height requested by its LayoutParams.
Related
I want to combine images by putting them on top of eachother in Canvas and then view the combination using ImageView. What I know is if you set the first Bitmap into the Canvas everything else you do will be added to that first Bitmap. I only get the error:
PointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
ImageView mainImage = (ImageView) view.findViewById(R.id.mainImage);
Bitmap bottomImage = BitmapFactory.decodeFile("image1.png");
Bitmap topImage = BitmapFactory.decodeFile("image2.png");
Bitmap tempBitmap = Bitmap.createBitmap(bottomImage.getWidth(), bottomImage.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(bottomImage, 0, 0, null);
tempCanvas.drawBitmap(topImage, 0, 0, null);
mainImage.setImageBitmap(bitmap);
Try Below Code
public Bitmap drawImageOnImage(Bitmap background, Bitmap pic, int x_to_draw, int y_to_draw, int width, int height)
{
try
{
Canvas newCanvas = new Canvas(background);
Bitmap img_bitmap = Bitmap.createScaledBitmap(pic, width, height, true);
newCanvas.drawBitmap(img_bitmap, x_to_draw, y_to_draw,new Paint());
}catch (Exception e)
{
System.out.println("Error Occured=>");
e.printStackTrace();
}
return background;
}
Here function takes 2 input bitmaps, Background bitmap and another image bitmap to draw over background bitmap. You will get combined bitmap to set for ImageView. X and Y are the co-rdinates where top image bitmap start paint. Same for height and width
After some experiments this code worked perfectly. And I added multiple top images.
private void drawAndView(ImageView imgView, Bitmap bottomImage, Bitmap[] topImages){
Bitmap tempBitmap = Bitmap.createBitmap(bottomImage.getWidth(), bottomImage.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(bottomImage, 0, 0, null);
for (Bitmap bitmap : topImages){
tempCanvas.drawBitmap(bitmap, 0, 0, null);
}
imgView.setImageBitmap(tempBitmap);
}
In my code, I have a LinearLayout with many TextViews (like a table). And I try to convert this to Bitmap. there is my code:
public static Bitmap convertToBitmap(LinearLayout view){
view.measure(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
view.draw(c);
return bitmap;
}
But, there is a problem.
Views witch has setSingleLine(true) not display text in bitmap.
Exactly, the problem is in setHorizontallyScrolling(true), which is calling in setSingleLine code...
I try use .setScrollTo(X), but what exactly X must be. X = 0 - not works.
Is there any, who knows how fix it?
EDIT: TextViews has fixed Width.
EDIT: Problem is only for TextViews with Gravity = Center. With gravity Left all's ok.
Try one of this code? It's a bit different from the one you posted above.
/**
* this actually also provided by Romain Guy, but let's try another for performance improvements
*/
public static Bitmap getBitmapFromView(View view, int width, int height) {
view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
// Build the Drawing Cache
view.buildDrawingCache();
// Create Bitmap
Bitmap drawingCache = view.getDrawingCache();
if (drawingCache == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(drawingCache);
drawingCache.recycle();
view.setDrawingCacheEnabled(false);
return bitmap;
}
/**
* This method provided by Romain Guy, so it should do the job better, especially it includes case for listViews
*/
public static Bitmap getBitmapFromView(View view, int width, int height) {
//Pre-measure the view so that height and width don't remain null.
view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
//Assign a size and position to the view and all of its descendants
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
// Create bitmap
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
//Create a canvas with the specified bitmap to draw into
Canvas canvas = new Canvas(bitmap);
// if it's scrollView we get gull size
canvas.translate(-view.getScrollX(), -view.getScrollY());
//Render this view (and all of its children) to the given Canvas
view.draw(canvas);
return bitmap;
}
I'm trying to take a screenshot of the contents of a LinearLayout. The layout contains a scrollview that can be of variable height/width. This code works fine when the layout is not too big (i.e. you don't need to scroll very much off screen to see everything):
View v1 = (LinearLayout)theLayout;
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
However, if the LinearLayout that I'm trying to capture is large, then the application crashes with a null pointer on v1.getDrawingCache().
There is an error in logcat:
05-11 13:16:20.999: W/View(17218): View too large to fit into drawing
cache, needs 4784400 bytes, only 3932160 available
How can I properly take a screenshot of this layout? Is there another way to go about it that doesn't use so much memory?
Here's what ended up working for me to capture a large off-screen view in it's entirety:
public static Bitmap loadBitmapFromView(View v)
{
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
return b;
}
It's similar to the answer here, except that I use the view's width/height to create the bitmap
As the original question is talking about a ScrollView I just though I would add the following for anyone that was having problems getting the full height. To get the height of the ScrollView, the v.getHeight doesn't work, you need to use:
v.getChildAt(0).getHeight()
so the full thing would be:
ScrollView scrollView = (ScrollView) result.findViewById(R.id.ScrlView);
loadBitmapFromView(scrollView);
public static Bitmap loadBitmapFromView(View v)
{
int height = v.getChildAt(0).getHeight()
int width = v.getWidth()
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
return b;
}
Just using v.getHeight just gets the screen height, not the full height of the ScrollView.
While trying to make a screen shot of a custom view,I got the IllegalArgumentException : width and height must be >0. Here is what I wrote :
bitmap = loadBitmapFromView(v1);//v1 the custom view I want to picture.
public static Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
return b;
}
The line in which there is the exception : Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Of course the screen shot code is executed after the view is showed,on the next_act button code
The width and height of LayoutParams can be a constant such as FILL_PARENT, and they are negative numbers.
To get the view's measured dimensions you can use:
v.getMeasuredWidth() and v.getMeasuredHeight()
However, it depends on what you're after, and whether the view has been measured.
It would probably make more sense to wait until the view has been drawn, before taking the screenshot ;-) But you'd need to explain more about your use case.
I have researched to find solution to take a snapshot of current activity and I found 2 solutions to taking a snapshot, but all of them can't help me get right thing which I want.
My activity use camera, and I show 3D object in that layout (same as AR, but not use marker, just draw 3D object in camera frame).
So when I use found solutions, I just get Parent layout (RelativeLayout which I use to keep both camera and 3D object) with some other objects (some button), that bitmap same as physical design screen of XML file.
I used this solution to get snapshot:
private Bitmap takeScreenShot(Activity activity)
{
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap b1 = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = activity.getWindowManager().getDefaultDisplay().getWidth();
int height = activity.getWindowManager().getDefaultDisplay().getHeight();
Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();
return b;
}
and this solution:
public Bitmap snap() {
Bitmap bitmap = Bitmap.createBitmap(this.view.getWidth(), this.view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
But I got same result.
Please help me to find good solution to resolve this problem.
Thanks.