I am using the HelloAR demo application and I am trying to take a screenshot of the entire screen (menu bar and everything). I am able to take a screenshot, but not everything is captured... GUI elements are visible in the screenshot, but the camera feed is not.
Here is my code:
int counter = 0;
private void takeScreenShot()
{
View view = getWindow().getDecorView().getRootView();
Bitmap bmp = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
PixelCopy.request(getWindow(), bmp, copyResult -> {
if(copyResult == PixelCopy.SUCCESS){
String filename = getExternalFilesDir(null) + File.separator + "SCREENSHOTS" + File.seperator + "SS_" + counter + ".png";
store(bmp, filename);
counter++;
}
}, new Handler());
}
public static void storeit(Bitmap bm, String fileName){
File file = new File(fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 85, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
}
And here is what the screenshot looks like:
How can I capture the entire screen (camera feed, UI elements, menu bar, etc.)?
You could use MediaProjection to capture the screen contents.
This has the drawback of requesting the user for screen sharing permission.
(Reference SO answer with example)
Alternatively, you could get the content of the GLSurfaceView using glReadPixels fn & superimpose your existing View image over it.
(Reference SO answer with example)
The reason your current implementation doesn't work is because
SurfaceView and GLSurfaceView punch holes in their windows to allow their surfaces to be displayed (Android src reference). In other words, they have transparent areas.
So you cannot capture an image by calling GLSurfaceView.getDrawingCache().
If you want to get an image from GLSurfaceView, you should invoke glReadPixels() in GLSurfaceView.onDrawFrame().
Related
I have an app that displays live video streaming from a camera device on the Surface view. As I am not an expert on Android, it took me weeks to display live streaming content on the Surface view. The format is raw H.264. I used Mediacodec to decode. What I need is to record that live streaming video and capture a screenshot of the same on a button click.
Code for taking a screenshot:
private void takeScreenshot() {
Date now = new Date();
android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
try {
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(mPath);
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
openScreenshot(imageFile);
} catch (Throwable e) {
// Several error may come out with file handling or DOM
e.printStackTrace();
}
}
private void openScreenshot(File imageFile) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(imageFile);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
}
Using the above code I am able to take a screenshot but the image color is black and also contains other buttons that I am using. All the other buttons are placed on top of the Surface view.
Is it possible to record and capture only the contents(excluding the buttons on top of the Surface view) that are displayed on the Surface view?
I am just thinking, please correct me if I am wrong. Instead of displaying it on SurfaceView, Is there any way to record and capture the decoded frames directly? Please find the below code:
This is how I display streaming content on SurfaceView;
LinearLayout surface2 = (LinearLayout)findViewById(R.id.surface);
SurfaceView sv = new SurfaceView(this);
sv.getHolder().addCallback(this);
surface2.addView(sv);
A moment when I click a notification bar, I want app to capture current screen. But i want the app capture 'after the notification bar disappears'. And I want that captured screen to be saved and loaded right after and showed up. How shoud i do?
For example code just do template of "new full screen activity" this will show you how to show/hide toolbar and make full screen.
Then just modify the code so it doesn't happen on a timer, instead move it to a touch listener that you place on the toolbar itself.
Lastly, once the fade has disappeared (which you can do instant if you want) then simply make your own screenshot. There are plenty of great libraries that will do this for you if you want or you can use simple code that I put in a class I named ImageHelper like this:
public static Bitmap takeScreenshotOfView(Activity context, Bitmap.CompressFormat compressFormat){
Bitmap screenshot = null;
try {
// create bitmap screen capture
View v1 = context.getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
screenshot = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(context.getFilesDir() + File.separator + "A35_temp" + File.separator + "screenshot_temp");
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
screenshot.compress(compressFormat, quality, outputStream);
outputStream.flush();
outputStream.close();
} catch (Throwable e) {
// Several error may come out with file handling or OOM
e.printStackTrace();
}
return screenshot;
}
And just use it like:
Bitmap screenshot = ImageHelper.takeScreenshotOfView(this, Bitmap.CompressFormat.JPEG);
Next start a fullScreen Activity new for Preview but default with toolbar hidden and fullscreen ImageView with your share overlay buttons or whatever you want at the bottom.
I'm trying to make a little Android app that triggers a screenshot capture of the current showing screen when a specific notification appears. For example, I'm on whatsapp and a Whatsapp notification appears -> That triggers a whatsapp capture.
Well, my current code actually detects notifications and triggers a screenshot when a notification comes, but not the way I want. I get a screenshot of my MainActivity, even if it's not showing on the screen. I just want to screenshot what it's appearing on the screen. It seems easy but I'm not being able to do it!
I leave my current NotificationReceiver class, which is failing because it captures the MainActivity and not the screen:
class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String temp = intent.getStringExtra("notification_event") + "\n" + txtView.getText();
txtView.setText(temp);
if (intent.getStringExtra("notification_event").contains("bet")) {
Log.i("Dentro", "dentro");
Date now = new Date();
android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
try {
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(mPath);
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
} catch (Throwable e) {
// Several error may come out with file handling or OOM
Log.i("Catch","Error dentro del if(contains)");
e.printStackTrace();
}
}//fin if
}
}
Any ideas of how can I proceed? I'm actually stuck. Help would be really appreciated!
You would need to use the media projection APIs on Android 5.0+, and set your minSdkVersion to 21. For privacy and security reasons, apps cannot take screenshots of other apps without explicit user permission, and that only became possible with Android 5.0.
This sample app demonstrates taking screenshots on demand.
For an app I'm trying to make I need to periodically capture screenshots of a widget (which my app would be the host of). But I want these screenshots to be captured without waking up the screen.
Essentially I want to refresh the widget, capture screenshot and then send it over the Internet while the phone screen is off.
Edit: Is it possible to load a widget, and then access its view (in order to generate a screenshot of the view) all while the phone's screen is off / locked?
You should be able to so long as you have an instance of the view. I'm not 100% sure the view's canvas remains drawn with the screen off though. Worth a shot. Here's some code I use to grab view screenshots over the web (note the compression differences for different view sizes)
public static byte[] captureScreenshot(View view) throws JSONException {
//maybe do something with filename
String fileName = null;
try {
// create bitmap screen capture
Bitmap bitmap;
view.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Bitmap.CompressFormat compressionFormat;
int filename = view.getId();
if (filename == -1) {
filename = 1010;
}
if (getBitMapSize(bitmap) > 750000) {
compressionFormat = Bitmap.CompressFormat.JPEG;
fileName = String.valueOf(filename) + ".jpg";
} else {
compressionFormat = Bitmap.CompressFormat.PNG;
fileName = String.valueOf(filename) + ".png";
}
bitmap.compress(compressionFormat, 60, outputStream);
byte[] imageBytes = outputStream.toByteArray();
} catch (Exception e) {
Log.e("Error creating screenshot: ");
}
return byte[];
So i was searching for a way to take a screenshot without root
i found this question stackoverflow question
mr Robin who answered this question said
" you can only get the screen shot of your own process"
1- yes i want to take a screen shot for my own presses may anyone provide some code that does not require root ?
2- my idea is to make a transparent activity and then use the in app screen shot is that possible ?
3- another thing is their is anyway to take a screen shot without root and without being at the foreground ? i had seen many apps on play store that can take a screen shot and does not require root ? any ideas ?
Try this:
public static Bitmap screenshot(final View view) {
view.setDrawingCacheEnabled(true);
view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_LOW);
view.buildDrawingCache();
if (view.getDrawingCache() == null) {
return null;
}
final Bitmap screenshot = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
view.destroyDrawingCache();
return screenshot;
}
Original code: https://stackoverflow.com/a/5651242/603270
Considering that we want to take the screenshot when a button is clicked, the code will look like this:
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Bitmap bitmap = takeScreenshot();
saveBitmap(bitmap);
}
});
First of all we should retrieve the topmost view in the current view hierarchy, then enable the drawing cache, and after that call getDrawingCache().
Calling getDrawingCache(); will return the bitmap representing the view or null if cache is disabled, that’s why setDrawingCacheEnabled(true); should be set to true prior invoking getDrawingCache().
public Bitmap takeScreenshot() {
View rootView = findViewById(android.R.id.content).getRootView();
rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
}
And the method that saves the bitmap image to external storage:
public void saveBitmap(Bitmap bitmap) {
File imagePath = new File(Environment.getExternalStorageDirectory() + "/screenshot.png");
FileOutputStream fos;
try {
fos = new FileOutputStream(imagePath);
bitmap.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e("GREC", e.getMessage(), e);
} catch (IOException e) {
Log.e("GREC", e.getMessage(), e);
}
}
Since the image is saved on external storage, the WRITE_EXTERNAL_STORAGE permission should be added AndroidManifest to file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />