I want to take a screen shot of my Activity and components of Activity (View).
This Activity contains a SurfaceView and a layout on the top of each other.
When I take screen shot of Surface view it works well, but when I take screen shot of whole Activity I do not get the surface view in it. I am using the following code:
public class Screenshot {
private final View view;
/** Create snapshots based on the view and its children. */
public Screenshot(View root) {
this.view = root;
}
/** Create snapshot handler that captures the root of the whole activity. */
public Screenshot(Activity activity) {
final View contentView = activity.findViewById(android.R.id.content);
this.view = contentView.getRootView();
}
/** Take a snapshot of the view. */
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;
}
}
What you can do as a workaround is capture both the layout and the SurfaceView images and draw the SurfaceView image over the layout image (using Canvas.drawBitmap) at the right coordinates using the properties of the SurfaceView.
Change this.view = contentView.getRootView(); to this.view = contentView;
Hope it will help.
I'm not sure if this is going to help or not but can't you just take the screen shot using DDMS directly?
EDIT
Have you tried getting the Window for the Activity and seeing what views/image cache you can pull out of that?
Related
I am using Jetpack's GameActivity to render my game in Android, and I am adding some native views on the top of it in the Kotlin code. I would like a way to capture the entire screen as a Bitmap, but somehow the OpenGL rendered things do not appear on the saved Bitmap, just the "normal" Android View's.
This is how I am doing to capture the Bitmap:
private fun captureGameImage(v: View): Bitmap {
val b = Bitmap.createBitmap(v.width, v.height, Bitmap.Config.ARGB_8888)
val c = Canvas(b)
v.draw(c)
return b
}
on my onCreate this is how I get the rootView, which I later on send to this method. I inflate the overlay layout and add to it:
val overlayViews = layoutInflater.inflate(R.layout.widgets, null)
rootView = (findViewById<View>(android.R.id.content) as ViewGroup)
rootView.addView(overlayViews)
Then at some point I invoke:
captureGameImage(rootView)
Again, the created Bitmap has all the views that are on the overlayViews, but the game itself is not there. I even debugged the captureGameImage function and indeed the v has two children views, the game one and the overlay one, but somehow the game one doesn't get captured in the Bitmap.
Any ideas how to capture the entire view, including the game rendered stuff?
You might be able to disable SurfaceView rendering by overriding the GameActivity.onCreateSurfaceView() in your own derived Activity:
final var mContentView: View? = null
/**
* Creates an empty View for the launching activity, prevent GameActivity from creating the
* default SurfaceView.
*/
#Override
protected void onCreateSurfaceView() {
mSurfaceView = null;
getWindow().takeSurface(this);
mContentView = new View(this);
setContentView(mContentView);
mContentView.requestFocus();
}
Then do your capturing, and put it back for your production version for the performance gains with the SurfaceView.
I making ane which makes screenshot of application. But I always getting black rectangle.
public class TakeScreenshot implements FREFunction {
#Override
public FREObject call(FREContext context, FREObject[] args) {
try {
View view = context.getActivity().getWindow().getDecorView().getRootView();
view.setDrawingCacheEnabled(true);
Bitmap cachedBitmap = Bitmap.createBitmap(view.getDrawingCache());
Bitmap bitmap = cachedBitmap.copy(cachedBitmap.getConfig(), false);
FREBitmapData bmd = (FREBitmapData)args[0];
bmd.acquire();
bitmap.copyPixelsToBuffer(bmd.getBits());
bmd.release();
bmd.invalidateRect(0,0, bitmap.getWidth(), bitmap.getHeight());
return bmd;
} catch (FREWrongThreadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Guess, the problem is in taking correct View from FREContext.
Have tried different ways to take View with same result:
View view = context.getActivity().getWindow().getDecorView();
View view = context.getActivity().findViewById(android.R.id.content);
View view = context.getActivity().findViewById(android.R.id.content).getRootView();
Unfortunately you cannot capture SurfaceView renders using this method which is how AIR renders its content.
SurfaceView's will always render as black / empty content using the drawing cache. They contain 2 parts, a placeholder View and the render surface. The drawing cache method only captures the view part which is empty.
On API 21 and higher you can use the MediaProjection class to perform a screencapture using a virtual display.
This is the method we use in our Image ANE that can capture a screenshot:
https://airnativeextensions.com/extension/com.distriqt.Image
I have the same problem. I'm playing a local video but in Adobe Air Android I need to take a screenshot (BITMAPDATA.draw(this);) the video turns black
I started with the sample code CurrentPlaceDetailsOnMap from here:
CurrentPlaceDetailsOnMap
I changed it adding an image to the info view. and then I tried to load the image in the getInfoContents
#Override
public View getInfoContents(final Marker marker) {
// Inflate the layouts for the info window, title and snippet.
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents, (FrameLayout)findViewById(R.id.map), false);
TextView title = ((TextView) infoWindow.findViewById(R.id.title));
title.setText(marker.getTitle());
TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
snippet.setText(marker.getSnippet());
final ImageView imageView = ((ImageView) infoWindow.findViewById(R.id.image));
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Bitmap bitmap = getBitmap(MapsActivityCurrentPlace.this, R.drawable.my_bitmap;
imageView.setImageBitmap(bitmap);
}
});
return infoWindow;
}
In the code above I used the Handleronly to simulate what happens when I load the image asynchronously by calling Places.GeoDataApi.getPlacePhotos.
The result is that the image is not shown.
If I call:
Bitmap bitmap = getBitmap(MapsActivityCurrentPlace.this, R.drawable.my_bitmap;
imageView.setImageBitmap(bitmap);
synchronously everything is fine.
It looks like google Map caches the view creating an image of the entire view. From the doc:
Note: The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later (for example, after an image has loaded), call showInfoWindow(). Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below.
How can I set the image in the InfoView?
The only solution I found so far is to load the bitmap in advance and to store it in a cache and then assign the bitmap to the infoview.imageView synchronously.
But this means that I have to load the images in advance.
New Android programmer here.
I'm trying to display an .png image as a bitmap on Android. The only way I have been able to display the converted image at all is with a custom class that extends View. However, my image is too large to be displayed entirely on the screen and I would like to be able to scroll with it. But when I define a ScrollView and put the Canvas with the Bitmap into it, I get a blank screen. I had no luck setting this up with the layout file, so it is all done in the Activity class.
This is where the Activity is created:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView scroll = new ScrollView(this);
scroll.addView(new CustomView(this));
setContentView(scroll);
}
And this is my CustomView class:
private class CustomView extends View{
public CustomView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas){
Bitmap bitmapMap = BitmapFactory.decodeResource(getResources(),R.drawable.resourceimage);
canvas.drawBitmap(bitmapMap,0,0,null);
this.setWillNotDraw(false);
}
}
And if I replace this line of code in my Activity: setContentView(scroll)
with this line: setContentView(new CustomView(this)), I can see the image, albeit not the entire image. So, is there a way to set this up in the layout files instead? Or is there something I'm missing that I need to declare in the ScrollView class?
EDIT: I would prefer not to use ImageView, because I would like to change the image in specific locations, and using bitmap seemed to be the easiest way to accomplish that, via x and y coordinates.
Your custom view needs to override the onMeasure method and properly set the measured width and height so that the parent views (in this case the ScrollView) can know how much space to allocate for the child.
I am attempting to create a user interface dynamically. I have successfully create a view and loaded my background image. I have created two additional small view items to display on the background. My problem is that I have not been able to find any advice/instruction that tells me how to draw the small views. It seems that it should be a trivial exercise and I am guessing it is just finding the correct referencing. Hope someone out there can point me in the right direction.
Here is my Activity:
public class GhostActivity extends Activity implements OnTouchListener
{
private DrawView ghostView;
public Card mCard1, mCard2;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
// ToDo add your GUI initialization code here
super.onCreate(savedInstanceState);
// requesting to turn the title OFF
requestWindowFeature(Window.FEATURE_NO_TITLE);
// making it full screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
ghostView = new DrawView(this);
setContentView(ghostView);
//get the window size
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Context context = getApplicationContext();
//create view items with initial positions
Point startPoint;
startPoint = new Point();
startPoint.x = 5;
startPoint.y = 3;
mCard1 = new Card(context, 1, R.drawable.bol_geel, startPoint);
startPoint.x = 5;
startPoint.y = 43;
mCard2 = new Card(context, 2, R.drawable.bol_rood, startPoint);
//now display them on the ghostView *****************HOW?
// set the callbacks
ghostView.setOnTouchListener(this);
mCard1.setOnTouchListener(this);
mCard2.setOnTouchListener(this);
}
and here is the View;
public class DrawView extends View
{
Drawable bg ;
public DrawView(Context context) {
super(context);
//setFocusable(true);
Drawable bg = this.getResources().getDrawable(R.drawable.bubbleblue480x800);
setBackgroundDrawable(bg);
}
#Override protected void onDraw(Canvas canvas) {
// canvas.drawColor(0x0000000); //if you want another background color
//draw on the canvas
}
}
edit: I believe my problem is needing to pass a pointer to the ghostView canvas. what makes me think that is if I create the children within ghostView then call their .draw method they appear exactly as I would expect.
#Override protected void onDraw(Canvas canvas) {
canvas.drawColor(0x0000000); //if you want another background color
//draw the cards on the canvas
mCard1.draw(canvas);
mCard2.draw(canvas);
}
so at this point I am wondering how to get a reference pointer to the ghostView canvas.
To be honest I am finding the whole Activity - View relationship confusing.
Edit: I have taken a different approach based on detail in this tutorial
http://www.kellbot.com/2009/06/android-hello-circle/
It uses a FrameLayout and it seems I can achieve my objective.
To add view dynamically to view your class must extends from ViewGroup or LinearLayout class then you will able to call method addView.
Inside your ghost view first add a layout e.g Linear or Relative. Then only you could able to add views inside that layout you cant simply add a view to a xml file.
Or you can create a dynamic layout then only u can add view inside that layout.
RelativeLayout relative= new RelativeLayout(findViewById(R.id.your relativeLayoutID));
relative.addView(child);
child could be anything button textview and widget.