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.
Related
Hi all I have a problem in displaying image in ImageView when clicked, i made a function to display whenever the image was click I have already added the android:onClick="drops" in .xml in every imageview of my sample game, i used gridlayout(3x3) with 9 imageview
here is the code of the function.
fun drops(view: View){
val imageView = ImageView(this)
var player = 0;
if (player == 0){
imageView.setImageResource(R.drawable.yellow)
imageView.animate().alpha(1f).rotation(360f).setDuration(600)
player == 1
}else {
imageView.setImageResource(R.drawable.red)
imageView.animate().alpha(1f).rotation(360f).setDuration(600)
player == 0
}
}
I'm unsure in what class is this function contained, I suppose it is either in a Fragment or Activity. As you said, you're binding the image views with drops method in the xml layout.
What could be the problem is this line:
val imageView = ImageView(this)
From your question we cannot see which class is this method defined in, so expression this could be anything. You might me instantiating an ImageView from the whole Activity or Fragment object, and cannot work in way you would like to. So I suggest to rewrite this line to something like this:
val imageView = view as ImageView
The function drops receives a single View parameter, which is the image view the user clicked - but View class has no method called setImageResource, so you need to cast it to the desired subtype (ImageView is subclass of View). This should do the job.
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 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?
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.
I'm trying to insert a View behind another view that is taking up the full screen and then later removing the view in the front to reveal the only remaining view. Functionally, everything is working as expected but the problem is that when I call View.addView() to add the second view, specifying to add it at index 0 so it is behind the first view, the screen flickers. It's almost as if the view is actually getting added in front of the first view for a fraction of a second and then it is hidden again as it is moved behind it.
Here's what I'm doing:
When the Activity is created I add an ImageView to a RelativeLayout and make the RelativeLayout instance the Activity's content view:
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
m_layout = new RelativeLayout(this);
m_layout.setBackgroundColor(Color.BLACK);
m_splashImage = new ImageView(this);
m_splashImage.setImageResource(R.drawable.splash);
m_splashImage.setScaleType(ScaleType.FIT_XY);
m_layout.addView(m_splashImage,
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
setContentView(m_layout);
}
When the Activity is started, I created and add the GLSurfaceView to the RelativeLayout at index 0, so it is behind the ImageView:
protected void onStart() {
super.onStart();
m_layout.addView(new MyGLSurfaceView(), 0,
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
}
Later, after all of the loading is done and the GLSurfaceView is ready to continuously render,
the splash ImageView is removed and cleaned up.
public void hideSplashScreen() {
if (m_splashImage != null) {
m_layout.removeView(m_splashImage);
m_splashImage = null;
}
}
Is there a better way to do this that doesn't require creating the GLSurfaceView before the onStart() is called?
Have you tried using view.setVisibility(View.GONE) on of the view that you adding behind? Of course before you are adding it.