Take screenshot of current showing screen, NOT the current activity - android

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.

Related

Android screenshot not capturing everything

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().

Save Screenshot into Internal Storage and Sync into Gallery?

I have searched high and low for a way to do this and the best I could find involved saving the screenshot into the SD Card. What I want to do instead is to onclick(), take a screenshot of the current activity and saves it in the internal storage so that the user can view it in their gallery as and when they want.
Any help is greatly appreciated.
It is harder to post a whole code in here. I think you should follow some tutorials.
According to the your requirement what I got is, You need to take a screenshot using an your application and it should be stored in device SD card.
For that you should add proper permission to the manifest first,
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
and add following code to the activity:
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, you can change it to your path
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) {
e.printStackTrace();
}
}
this code will open the generated image(screenshot):
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);
}
This is how I did for my project. Sometimes this might be not satisfied for you requirement. It it is not satisfied, please follow these tutorials, Thanks
Reference List : http://www.androhub.com/take-a-screenshot-programmatically-in-android/
http://devdeeds.com/take-screenshot-programmatically/
https://www.viralandroid.com/2016/01/how-to-take-screenshot-programmatically-in-android.html
if you want to check whether SD card is available or not. here is the way. If SD card is not available then you can use internal storage to store the image.
Boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if(isSDSupportedDevice && isSDPresent)
{
// yes SD-card is present
}
else
{
// SD-card not available
}

How can I get the device orientation when a photo was taken

I've never been struggling this much with images as I am today and I'd appreciate some help :D
So, thing is, I'm using the built-in camera to capture a picture and then send it to the back end to save it but the orientation is messed up for Kit kat and specially Samsung devices. I tried to use the exif interface everyone suggests, but I just can't get the photo orientation.
A few minutes ago I found an answer somewhat related to this, saying that maybe a good solution is to save the device orientation when the picture is taken, which sounds pretty nice, however, I don't know how to do that with the built in camera, since I don't have full control when opening the camera with an Intent, like this:
mPathToTakenImage = ImageProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider",
newFile);
openCamera.putExtra(MediaStore.EXTRA_OUTPUT, mPathToTakenImage);
openCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(openCamera, AlgebraNationConstants.TAKE_PHOTO_REQUEST_CODE);
So, how can I get the device orientation while the image was being taken in order to rotate the image correctly?
This is the code to rotate the image, however, I'm getting always zero:
final Bitmap finalImg;
final StringBuilder base64Image = new StringBuilder("data:image/jpeg;base64,");
final ExifInterface exifInterface;
try {
final String imagePath = params[0].getPath();
exifInterface = new ExifInterface(imagePath);
final int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
final Bitmap takenPhoto = MediaStore.Images.Media.getBitmap(mRelatedContext.getContentResolver(),
params[0]);
if (null == takenPhoto) {
base64Image.setLength(0);
} else {
finalImg = rotateBitmap(takenPhoto, orientation);
if (null == finalImg) {
base64Image.setLength(0);
} else {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
finalImg.compress(Bitmap.CompressFormat.JPEG, 75, byteArrayOutputStream);
final byte[] byteArray = byteArrayOutputStream.toByteArray();
base64Image.append(Base64.encodeToString(byteArray, Base64.DEFAULT));
}
}
} catch (IOException e) {
e.printStackTrace();
}
return base64Image.length() == 0 ? null : base64Image.toString();
I'm going crazy with this, any help will be deeply appreciated.
EDIT:
A Uri is not a file. Unless the scheme of the Uri is file, getPath() is meaningless. In your case, the scheme is mostly going to be content, not file. As it stands, you are not getting EXIF headers, because ExifInterface cannot find that file.
Use a ContentResolver and openInputStream() to open an InputStream on the content identified by the Uri. Pass that InputStream to the android.support.media.ExifInterface constructor.
Also, bear in mind that you will crash much of the time with an OutOfMemoryError, as you will not have heap space to hold a base64-encoded photo.
So, I finally resolved my problem making use of these two answers:
https://stackoverflow.com/a/17426328
https://stackoverflow.com/a/40865982
In general, the issue was due to the image allocation in disk since I don't know why Android didn't like the fact that I was giving my own path to save the taken image. At the end, the Intent to open the camera is looking like this:
final Intent openCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(openCamera, AlgebraNationConstants.TAKE_PHOTO_REQUEST_CODE);
And Android itself is resolving where to put the image. Nevertheless, #CommonsWare thanks for the enlightenment and answers.

A moment when I click a notification bar, I want app to capture current screen

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.

Is it possible to capture a screenshot of a widget while the device screen is off?

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[];

Categories

Resources