How can I take a screenshot of a selected area of phone-screen not by any program but from code?
Here is the code that allowed my screenshot to be stored on an SD card and used later for whatever your needs are:
First, you need to add a proper permission to save the file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
And this is the code (running in an 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
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();
}
}
And this is how you can open the recently generated image:
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);
}
If you want to use this on fragment view then use:
View v1 = getActivity().getWindow().getDecorView().getRootView();
instead of
View v1 = getWindow().getDecorView().getRootView();
on takeScreenshot() function
Note:
This solution doesn't work if your dialog contains a surface view. For details please check the answer to the following question:
Android Take Screenshot of Surface View Shows Black Screen
Call this method, passing in the outer most ViewGroup that you want a screen shot of:
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Note: works only for rooted phone
Programmatically, you can run adb shell /system/bin/screencap -p /sdcard/img.png as below
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
then read img.png as Bitmap and use as your wish.
No root permission or no big coding is required for this method.
On adb shell using below command you can take screen shot.
input keyevent 120
This command does not required any root permission so same you can perform from java code of android application also.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
More about keyevent code in android see http://developer.android.com/reference/android/view/KeyEvent.html
Here we have used. KEYCODE_SYSRQ its value is 120 and used for System Request / Print Screen key.
As CJBS said, The output picture will be saved in /sdcard/Pictures/Screenshots
Mualig answer is very good, but I had the same problem Ewoks describes, I'm not getting the background. So sometimes is good enough and sometimes I get black text over black background (depending on the theme).
This solution is heavily based in Mualig code and the code I've found in Robotium. I'm discarding the use of drawing cache by calling directly to the draw method. Before that I'll try to get the background drawable from current activity to draw it first.
// Some constants
final static String SCREENSHOTS_LOCATIONS = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
// Get device dimmensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get root view
View view = mCurrentUrlMask.getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Activity activity = getCurrentActivity();
final Theme theme = activity.getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = activity.getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
// Save the screenshot to the file system
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS
+ System.currentTimeMillis() + ".jpg");
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d(LOGTAG, "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
As a reference, one way to capture the screen (and not just your app activity) is to capture the framebuffer (device /dev/graphics/fb0). To do this you must either have root privileges or your app must be an app with signature permissions ("A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission") - which is very unlikely unless you compiled your own ROM.
Each framebuffer capture, from a couple of devices I have tested, contained exactly one screenshot. People have reported it to contain more, I guess it depends on the frame/display size.
I tried to read the framebuffer continuously but it seems to return for a fixed amount of bytes read. In my case that is (3 410 432) bytes, which is enough to store a display frame of 854*480 RGBA (3 279 360 bytes). Yes, the frame, in binary, outputted from fb0 is RGBA in my device. This will most likely depend from device to device. This will be important for you to decode it =)
In my device /dev/graphics/fb0 permissions are so that only root and users from group graphics can read the fb0.
graphics is a restricted group so you will probably only access fb0 with a rooted phone using su command.
Android apps have the user id (uid) = app_## and group id (guid) = app_## .
adb shell has uid = shell and guid = shell, which has much more permissions than an app. You can actually check those permissions at /system/permissions/platform.xml
This means you will be able to read fb0 in the adb shell without root but you will not read it within the app without root.
Also, giving READ_FRAME_BUFFER and/or ACCESS_SURFACE_FLINGER permissions on AndroidManifest.xml will do nothing for a regular app because these will only work for 'signature' apps.
Also check this closed thread for more details.
private void captureScreen() {
View v = getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
try {
FileOutputStream fos = new FileOutputStream(new File(Environment
.getExternalStorageDirectory().toString(), "SCREEN"
+ System.currentTimeMillis() + ".png"));
bmp.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Add the permission in the manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
For Supporting Marshmallow or above versions, please add the below code in the activity onCreate method
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
My solution is:
public static Bitmap loadBitmapFromView(Context context, View v) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
v.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
v.draw(c);
return returnedBitmap;
}
and
public void takeScreen() {
Bitmap bitmap = ImageUtils.loadBitmapFromView(this, view); //get Bitmap from the view
String mPath = Environment.getExternalStorageDirectory() + File.separator + "screen_" + System.currentTimeMillis() + ".jpeg";
File imageFile = new File(mPath);
OutputStream fout = null;
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
fout.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fout.close();
}
}
Images are saved in the external storage folder.
You can try the following library:
http://code.google.com/p/android-screenshot-library/
Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
Based on the answer of #JustinMorris above and #NiravDangi here https://stackoverflow.com/a/8504958/2232148 we must take the background and foreground of a view and assemble them like this:
public static Bitmap takeScreenshot(View view, Bitmap.Config quality) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), quality);
Canvas canvas = new Canvas(bitmap);
Drawable backgroundDrawable = view.getBackground();
if (backgroundDrawable != null) {
backgroundDrawable.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
view.draw(canvas);
return bitmap;
}
The quality parameter takes a constant of Bitmap.Config, typically either Bitmap.Config.RGB_565 or Bitmap.Config.ARGB_8888.
public class ScreenShotActivity extends Activity{
private RelativeLayout relativeLayout;
private Bitmap myBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout)findViewById(R.id.relative1);
relativeLayout.post(new Runnable() {
public void run() {
//take screenshot
myBitmap = captureScreen(relativeLayout);
Toast.makeText(getApplicationContext(), "Screenshot captured..!", Toast.LENGTH_LONG).show();
try {
if(myBitmap!=null){
//save image to SD card
saveImage(myBitmap);
}
Toast.makeText(getApplicationContext(), "Screenshot saved..!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public static Bitmap captureScreen(View v) {
Bitmap screenshot = null;
try {
if(v!=null) {
screenshot = Bitmap.createBitmap(v.getMeasuredWidth(),v.getMeasuredHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(screenshot);
v.draw(canvas);
}
}catch (Exception e){
Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
}
return screenshot;
}
public static void saveImage(Bitmap bitmap) throws IOException{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes);
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
}
}
ADD PERMISSION
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
You can try to do something like this,
Getting a bitmap cache from a layout or a view by doing something like
First you gotta setDrawingCacheEnabled to a layout(a linearlayout or relativelayout, or a view)
then
Bitmap bm = layout.getDrawingCache()
Then you do whatever you want with the bitmap. Either turning it into an image file, or send the bitmap's uri to somewhere else.
Short way is
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Most of the answers for this question use the the Canvas drawing method or drawing cache method. However, the View.setDrawingCache() method is deprecated in API 28. Currently the recommended API for making screenshots is the PixelCopy class available from API 24 (but the methods which accept Window parameter are available from API 26 == Android 8.0 Oreo). Here is a sample Kotlin code for retrieving a Bitmap:
#RequiresApi(Build.VERSION_CODES.O)
fun saveScreenshot(view: View) {
val window = (view.context as Activity).window
if (window != null) {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
saveBitmap(bitmap)
}
// possible to handle other result codes ...
}, Handler())
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
}
}
}
For those who want to capture a GLSurfaceView, the getDrawingCache or drawing to canvas method won't work.
You have to read the content of the OpenGL framebuffer after the frame has been rendered. There is a good answer here
I have created a simple library that takes a screenshot from a View and either gives you a Bitmap object or saves it directly to any path you want
https://github.com/abdallahalaraby/Blink
If you want to take screenshot from fragment than follow this:
Override onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_one, container, false);
mView = view;
}
Logic for taking screenshot:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View view = mView.findViewById(R.id.scrollView1);
shareScreenShotM(view, (NestedScrollView) view);
}
method shareScreenShotM)():
public void shareScreenShotM(View view, NestedScrollView scrollView){
bm = takeScreenShot(view,scrollView); //method to take screenshot
File file = savePic(bm); // method to save screenshot in phone.
}
method takeScreenShot():
public Bitmap takeScreenShot(View u, NestedScrollView z){
u.setDrawingCacheEnabled(true);
int totalHeight = z.getChildAt(0).getHeight();
int totalWidth = z.getChildAt(0).getWidth();
Log.d("yoheight",""+ totalHeight);
Log.d("yowidth",""+ totalWidth);
u.layout(0, 0, totalWidth, totalHeight);
u.buildDrawingCache();
Bitmap b = Bitmap.createBitmap(u.getDrawingCache());
u.setDrawingCacheEnabled(false);
u.destroyDrawingCache();
return b;
}
method savePic():
public static File savePic(Bitmap bm){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + "/Foldername");
if (!sdCardDirectory.exists()) {
sdCardDirectory.mkdirs();
}
// File file = new File(dir, fileName);
try {
file = new File(sdCardDirectory, Calendar.getInstance()
.getTimeInMillis() + ".jpg");
file.createNewFile();
new FileOutputStream(file).write(bytes.toByteArray());
Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath());
Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
For activity you can simply use View v1 = getWindow().getDecorView().getRootView(); instead of mView
Just extending taraloca's answer. You must add followings lines to make it work. I have made the image name static. Please ensure you use taraloca's timestamp variable incase you need dynamic image name.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private void verifyStoragePermissions() {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}else{
takeScreenshot();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_STORAGE) {
takeScreenshot();
}
}
}
And in the AndroidManifest.xml file following entries are must:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For Full Page Scrolling Screenshot
If you want to capture a full View screenshot (Which contains a scrollview or so) then have a check at this library
https://github.com/peter1492/LongScreenshot
All you have to do is import the Gradel, and create an object of BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
A callback will be received with the bitmap of the Screenshots taken while automatically scrolling through the screen view group and at the end assembled together.
#Override public void getScreenshot(Bitmap bitmap) {}
Which can be saved to the gallery or whatsoever usage is necessary their after
For system applications only!
Process process;
process = Runtime.getRuntime().exec("screencap -p " + outputPath);
process.waitFor();
Note: System applications don't need to run "su" to execute this command.
The parameter view is the root layout object.
public static Bitmap screenShot(View view) {
Bitmap bitmap = null;
if (view.getWidth() > 0 && view.getHeight() > 0) {
bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
}
return bitmap;
}
From Android 11 (API level 30) you can take screen shot with the accessibility service:
takeScreenshot - Takes a screenshot of the specified display and returns it via an AccessibilityService.ScreenshotResult.
Take screenshot of a view in android.
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
If you want to capture screenshot of a View, use View::drawToBitmap extension function:
val bitmap = myTargetView.drawToBitmap(/*Optional:*/ Bitmap.Config.ARGB_8888)
Only make sure to use the -ktx version of AndroidX Core library:
implementation("androidx.core:core-ktx:1.6.0")
I've already answered a similar question like this here.
Kotlin
private fun screenShot() {
try {
val mPath: String = this.getExternalFilesDir(null).getAbsolutePath()
.toString() + "/temp" + ".png"
// create bitmap screenshot
val v1: View = getWindow().getDecorView().getRootView()
v1.isDrawingCacheEnabled = true
val bitmap = Bitmap.createBitmap(v1.drawingCache)
v1.isDrawingCacheEnabled = false
val imageFile = File(mPath)
val outputStream = FileOutputStream(imageFile)
val quality = 100
bitmap.compress(Bitmap.CompressFormat.PNG, quality, outputStream)
outputStream.flush()
outputStream.close()
//or you can share to test the method fast
val uriPath =
FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile)
val intent = Intent(Intent.ACTION_SEND)
intent.type = "image/*"
intent.clipData = ClipData.newRawUri("", uriPath)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
intent.putExtra(Intent.EXTRA_STREAM, uriPath)
startActivity(Intent.createChooser(intent, "Sharing to..."))
} catch (e: Throwable) {
e.printStackTrace()
}
}
Java
private void screenShot() {
try {
String mPath = this.getExternalFilesDir(null).getAbsolutePath().toString() + "/temp" + ".png";
// create bitmap screenshot
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.PNG, quality, outputStream);
outputStream.flush();
outputStream.close();
//or you can share to test the method fast
Uri uriPath = FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.setClipData(ClipData.newRawUri("", uriPath));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, uriPath);
startActivity(Intent.createChooser(intent, "Sharing to..."));
} catch (Throwable e) {
e.printStackTrace();
}
}
If you want to capture a view or layout like RelativeLayout or LinearLayout etc.
Just use the code:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
now you can save this bitmap on device storage by :
FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
outStream = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
addImageGallery(file);
//mail.setEnabled(true);
flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
outStream.flush();
outStream.close();
} catch (IOException e) {e.printStackTrace();}
Related
How can I take a screenshot of a selected area of phone-screen not by any program but from code?
Here is the code that allowed my screenshot to be stored on an SD card and used later for whatever your needs are:
First, you need to add a proper permission to save the file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
And this is the code (running in an 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
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();
}
}
And this is how you can open the recently generated image:
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);
}
If you want to use this on fragment view then use:
View v1 = getActivity().getWindow().getDecorView().getRootView();
instead of
View v1 = getWindow().getDecorView().getRootView();
on takeScreenshot() function
Note:
This solution doesn't work if your dialog contains a surface view. For details please check the answer to the following question:
Android Take Screenshot of Surface View Shows Black Screen
Call this method, passing in the outer most ViewGroup that you want a screen shot of:
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Note: works only for rooted phone
Programmatically, you can run adb shell /system/bin/screencap -p /sdcard/img.png as below
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
then read img.png as Bitmap and use as your wish.
No root permission or no big coding is required for this method.
On adb shell using below command you can take screen shot.
input keyevent 120
This command does not required any root permission so same you can perform from java code of android application also.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
More about keyevent code in android see http://developer.android.com/reference/android/view/KeyEvent.html
Here we have used. KEYCODE_SYSRQ its value is 120 and used for System Request / Print Screen key.
As CJBS said, The output picture will be saved in /sdcard/Pictures/Screenshots
Mualig answer is very good, but I had the same problem Ewoks describes, I'm not getting the background. So sometimes is good enough and sometimes I get black text over black background (depending on the theme).
This solution is heavily based in Mualig code and the code I've found in Robotium. I'm discarding the use of drawing cache by calling directly to the draw method. Before that I'll try to get the background drawable from current activity to draw it first.
// Some constants
final static String SCREENSHOTS_LOCATIONS = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
// Get device dimmensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get root view
View view = mCurrentUrlMask.getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Activity activity = getCurrentActivity();
final Theme theme = activity.getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = activity.getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
// Save the screenshot to the file system
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS
+ System.currentTimeMillis() + ".jpg");
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d(LOGTAG, "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
As a reference, one way to capture the screen (and not just your app activity) is to capture the framebuffer (device /dev/graphics/fb0). To do this you must either have root privileges or your app must be an app with signature permissions ("A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission") - which is very unlikely unless you compiled your own ROM.
Each framebuffer capture, from a couple of devices I have tested, contained exactly one screenshot. People have reported it to contain more, I guess it depends on the frame/display size.
I tried to read the framebuffer continuously but it seems to return for a fixed amount of bytes read. In my case that is (3 410 432) bytes, which is enough to store a display frame of 854*480 RGBA (3 279 360 bytes). Yes, the frame, in binary, outputted from fb0 is RGBA in my device. This will most likely depend from device to device. This will be important for you to decode it =)
In my device /dev/graphics/fb0 permissions are so that only root and users from group graphics can read the fb0.
graphics is a restricted group so you will probably only access fb0 with a rooted phone using su command.
Android apps have the user id (uid) = app_## and group id (guid) = app_## .
adb shell has uid = shell and guid = shell, which has much more permissions than an app. You can actually check those permissions at /system/permissions/platform.xml
This means you will be able to read fb0 in the adb shell without root but you will not read it within the app without root.
Also, giving READ_FRAME_BUFFER and/or ACCESS_SURFACE_FLINGER permissions on AndroidManifest.xml will do nothing for a regular app because these will only work for 'signature' apps.
Also check this closed thread for more details.
private void captureScreen() {
View v = getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
try {
FileOutputStream fos = new FileOutputStream(new File(Environment
.getExternalStorageDirectory().toString(), "SCREEN"
+ System.currentTimeMillis() + ".png"));
bmp.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Add the permission in the manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
For Supporting Marshmallow or above versions, please add the below code in the activity onCreate method
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
My solution is:
public static Bitmap loadBitmapFromView(Context context, View v) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
v.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
v.draw(c);
return returnedBitmap;
}
and
public void takeScreen() {
Bitmap bitmap = ImageUtils.loadBitmapFromView(this, view); //get Bitmap from the view
String mPath = Environment.getExternalStorageDirectory() + File.separator + "screen_" + System.currentTimeMillis() + ".jpeg";
File imageFile = new File(mPath);
OutputStream fout = null;
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
fout.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fout.close();
}
}
Images are saved in the external storage folder.
You can try the following library:
http://code.google.com/p/android-screenshot-library/
Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
Based on the answer of #JustinMorris above and #NiravDangi here https://stackoverflow.com/a/8504958/2232148 we must take the background and foreground of a view and assemble them like this:
public static Bitmap takeScreenshot(View view, Bitmap.Config quality) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), quality);
Canvas canvas = new Canvas(bitmap);
Drawable backgroundDrawable = view.getBackground();
if (backgroundDrawable != null) {
backgroundDrawable.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
view.draw(canvas);
return bitmap;
}
The quality parameter takes a constant of Bitmap.Config, typically either Bitmap.Config.RGB_565 or Bitmap.Config.ARGB_8888.
public class ScreenShotActivity extends Activity{
private RelativeLayout relativeLayout;
private Bitmap myBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout)findViewById(R.id.relative1);
relativeLayout.post(new Runnable() {
public void run() {
//take screenshot
myBitmap = captureScreen(relativeLayout);
Toast.makeText(getApplicationContext(), "Screenshot captured..!", Toast.LENGTH_LONG).show();
try {
if(myBitmap!=null){
//save image to SD card
saveImage(myBitmap);
}
Toast.makeText(getApplicationContext(), "Screenshot saved..!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public static Bitmap captureScreen(View v) {
Bitmap screenshot = null;
try {
if(v!=null) {
screenshot = Bitmap.createBitmap(v.getMeasuredWidth(),v.getMeasuredHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(screenshot);
v.draw(canvas);
}
}catch (Exception e){
Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
}
return screenshot;
}
public static void saveImage(Bitmap bitmap) throws IOException{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes);
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
}
}
ADD PERMISSION
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
You can try to do something like this,
Getting a bitmap cache from a layout or a view by doing something like
First you gotta setDrawingCacheEnabled to a layout(a linearlayout or relativelayout, or a view)
then
Bitmap bm = layout.getDrawingCache()
Then you do whatever you want with the bitmap. Either turning it into an image file, or send the bitmap's uri to somewhere else.
Short way is
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Most of the answers for this question use the the Canvas drawing method or drawing cache method. However, the View.setDrawingCache() method is deprecated in API 28. Currently the recommended API for making screenshots is the PixelCopy class available from API 24 (but the methods which accept Window parameter are available from API 26 == Android 8.0 Oreo). Here is a sample Kotlin code for retrieving a Bitmap:
#RequiresApi(Build.VERSION_CODES.O)
fun saveScreenshot(view: View) {
val window = (view.context as Activity).window
if (window != null) {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
saveBitmap(bitmap)
}
// possible to handle other result codes ...
}, Handler())
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
}
}
}
For those who want to capture a GLSurfaceView, the getDrawingCache or drawing to canvas method won't work.
You have to read the content of the OpenGL framebuffer after the frame has been rendered. There is a good answer here
I have created a simple library that takes a screenshot from a View and either gives you a Bitmap object or saves it directly to any path you want
https://github.com/abdallahalaraby/Blink
If you want to take screenshot from fragment than follow this:
Override onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_one, container, false);
mView = view;
}
Logic for taking screenshot:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View view = mView.findViewById(R.id.scrollView1);
shareScreenShotM(view, (NestedScrollView) view);
}
method shareScreenShotM)():
public void shareScreenShotM(View view, NestedScrollView scrollView){
bm = takeScreenShot(view,scrollView); //method to take screenshot
File file = savePic(bm); // method to save screenshot in phone.
}
method takeScreenShot():
public Bitmap takeScreenShot(View u, NestedScrollView z){
u.setDrawingCacheEnabled(true);
int totalHeight = z.getChildAt(0).getHeight();
int totalWidth = z.getChildAt(0).getWidth();
Log.d("yoheight",""+ totalHeight);
Log.d("yowidth",""+ totalWidth);
u.layout(0, 0, totalWidth, totalHeight);
u.buildDrawingCache();
Bitmap b = Bitmap.createBitmap(u.getDrawingCache());
u.setDrawingCacheEnabled(false);
u.destroyDrawingCache();
return b;
}
method savePic():
public static File savePic(Bitmap bm){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + "/Foldername");
if (!sdCardDirectory.exists()) {
sdCardDirectory.mkdirs();
}
// File file = new File(dir, fileName);
try {
file = new File(sdCardDirectory, Calendar.getInstance()
.getTimeInMillis() + ".jpg");
file.createNewFile();
new FileOutputStream(file).write(bytes.toByteArray());
Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath());
Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
For activity you can simply use View v1 = getWindow().getDecorView().getRootView(); instead of mView
Just extending taraloca's answer. You must add followings lines to make it work. I have made the image name static. Please ensure you use taraloca's timestamp variable incase you need dynamic image name.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private void verifyStoragePermissions() {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}else{
takeScreenshot();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_STORAGE) {
takeScreenshot();
}
}
}
And in the AndroidManifest.xml file following entries are must:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For Full Page Scrolling Screenshot
If you want to capture a full View screenshot (Which contains a scrollview or so) then have a check at this library
https://github.com/peter1492/LongScreenshot
All you have to do is import the Gradel, and create an object of BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
A callback will be received with the bitmap of the Screenshots taken while automatically scrolling through the screen view group and at the end assembled together.
#Override public void getScreenshot(Bitmap bitmap) {}
Which can be saved to the gallery or whatsoever usage is necessary their after
For system applications only!
Process process;
process = Runtime.getRuntime().exec("screencap -p " + outputPath);
process.waitFor();
Note: System applications don't need to run "su" to execute this command.
The parameter view is the root layout object.
public static Bitmap screenShot(View view) {
Bitmap bitmap = null;
if (view.getWidth() > 0 && view.getHeight() > 0) {
bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
}
return bitmap;
}
From Android 11 (API level 30) you can take screen shot with the accessibility service:
takeScreenshot - Takes a screenshot of the specified display and returns it via an AccessibilityService.ScreenshotResult.
Take screenshot of a view in android.
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
If you want to capture screenshot of a View, use View::drawToBitmap extension function:
val bitmap = myTargetView.drawToBitmap(/*Optional:*/ Bitmap.Config.ARGB_8888)
Only make sure to use the -ktx version of AndroidX Core library:
implementation("androidx.core:core-ktx:1.6.0")
I've already answered a similar question like this here.
Kotlin
private fun screenShot() {
try {
val mPath: String = this.getExternalFilesDir(null).getAbsolutePath()
.toString() + "/temp" + ".png"
// create bitmap screenshot
val v1: View = getWindow().getDecorView().getRootView()
v1.isDrawingCacheEnabled = true
val bitmap = Bitmap.createBitmap(v1.drawingCache)
v1.isDrawingCacheEnabled = false
val imageFile = File(mPath)
val outputStream = FileOutputStream(imageFile)
val quality = 100
bitmap.compress(Bitmap.CompressFormat.PNG, quality, outputStream)
outputStream.flush()
outputStream.close()
//or you can share to test the method fast
val uriPath =
FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile)
val intent = Intent(Intent.ACTION_SEND)
intent.type = "image/*"
intent.clipData = ClipData.newRawUri("", uriPath)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
intent.putExtra(Intent.EXTRA_STREAM, uriPath)
startActivity(Intent.createChooser(intent, "Sharing to..."))
} catch (e: Throwable) {
e.printStackTrace()
}
}
Java
private void screenShot() {
try {
String mPath = this.getExternalFilesDir(null).getAbsolutePath().toString() + "/temp" + ".png";
// create bitmap screenshot
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.PNG, quality, outputStream);
outputStream.flush();
outputStream.close();
//or you can share to test the method fast
Uri uriPath = FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.setClipData(ClipData.newRawUri("", uriPath));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, uriPath);
startActivity(Intent.createChooser(intent, "Sharing to..."));
} catch (Throwable e) {
e.printStackTrace();
}
}
If you want to capture a view or layout like RelativeLayout or LinearLayout etc.
Just use the code:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
now you can save this bitmap on device storage by :
FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
outStream = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
addImageGallery(file);
//mail.setEnabled(true);
flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
outStream.flush();
outStream.close();
} catch (IOException e) {e.printStackTrace();}
I use this code in a service class to take screenshot in the service but getWindow() is not available here. what should i do?
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();
} catch (Throwable e) {
// Several error may come out with file handling or DOM
e.printStackTrace();
}
}
Try this approach:
Pass a reference to the activity when you create the class, and when calling relevant methods and use it. But there can be memory leaks with this approach
void MethodThatUsesActivity(Activity myActivityReference) {
myActivityReference.getWindow().getDecorView().getRootView();
}
I use below code to take screen shot from my layout and share it via android intent but the captured screen shot in the selected app is not showing any thing.
#Override
public void onClick(View view) {
shareBitmap(this,takeScreenshot());
}
public Bitmap takeScreenshot() {
try{
View rootView = getWindow().getDecorView().findViewById(R.id.lyt_main_report_activity);
rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
}catch (Exception ex){
ex.printStackTrace();
}
return null;
}
public static void shareBitmap(Context context, Bitmap bitmap){
//save to sd card
try {
File cachePath = new File(context.getCacheDir(), "images");
cachePath.mkdirs(); // don't forget to make the directory
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png"); // overwrites this image every time
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try{
//start share activity
File imagePath = new File(context.getCacheDir(), "images");
File newFile = new File(imagePath, "image.png");
Uri contentUri = Uri.fromFile(newFile); //FileProvider.getUriForFile(context, "com.persianswitch.apmb.app.fileprovider", newFile);
if (contentUri != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
//shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
// shareIntent.setDataAndType(contentUri, context. getContentResolver().getType(contentUri));
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.setType("image/*");
context.startActivity(Intent.createChooser(shareIntent, context.getResources().getString(R.string.share_using)));
}
}catch (Exception ex){
ex.printStackTrace();
}
}
Please use this code this is tested code :
public static void takeScreenshot(Context context, View view) {
String path = Environment.getExternalStorageDirectory().toString() +
"/" + "test.png";
View v = view.findViewById(android.R.id.content).getRootView();
v.setDrawingCacheEnabled(true);
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
OutputStream out = null;
File imageFile = new File(path);
try {
out = new FileOutputStream(imageFile);
// choose JPEG format
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
} catch (FileNotFoundException e) {
// manage exception
} catch (IOException e) {
// manage exception
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception exc) {}
}
// onPauseVideo();
Intent share = new Intent(Intent.ACTION_SEND);
share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
share.setType("image/png");
((Activity) context).startActivityForResult(
Intent.createChooser(share, "Share Drawing"), 111);
}
Since DrawingCache() deprecated above 28 so using Canvas will sort the issues for many. below answer can be used for share Screenshot including text without requesting for permissions.
To take the Screenshot
private Bitmap takeScreenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
To share the Screenshot
private void shareContent(Bitmap bitmap) {
String bitmapPath = MediaStore.Images.Media.insertImage(
binding.getRoot().getContext().getContentResolver(), bitmap, "title", "");
Uri uri = Uri.parse(bitmapPath);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "App");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Currently a new version of KiKi app is available.");
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
binding.getRoot().getContext().startActivity(Intent.createChooser(shareIntent, "Share"));
}
if nothing happens it means your Bitmap is null kindly check that. or you could also fall on View.buildDrawingCache(); which will draw the View to Bitmap and then call your View.getDrawingCache();
also When hardware acceleration is turned on, enabling the drawing cache has no effect on rendering because the system uses a different mechanism for acceleration which ignores the flag. If you want to use a Bitmap for the view, even when hardware acceleration is enabled, see setLayerType(int, android.graphics.Paint) for information on how to enable software and hardware layers.
the quote was taken from the documented page
hope it helps
Tipp:The checked answer works when your device has external storage. On the Samsung 6 for example, it doesnt. Therefore you need to work with fileprovider.
Just incase somebody fell into this trap like me. The problem is that you are putting the name of the image twice.
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png");
and than again.
File newFile = new File(imagePath, "image.png");
Change The seconed one to
File newFile = new File(imagePath);
Otherwise the contentUri give you the bitmap of your screenshot. I hope this helps someone. Took me 3 hours to figure it out :)
Hi StackOverflow community,
in my application I'd like to have a button which allows the user to capture the current view.
For that reason, I've written the following method (oriented towards: Android save view to jpg or png ):
private LinearLayout container;
public void createImageOfCurrentView(View v) {
if (isExternalStoragePresent()) {
container = (LinearLayout) findViewById(R.id.container);
container.setDrawingCacheEnabled(true);
Bitmap b = container.getDrawingCache();
File dir = new File(Environment.getExternalStorageDirectory().getPath()
+ "/" + getPackageName() + "/");
dir.mkdirs();
File file = new File(dir, "image.jpg");
FileOutputStream fos;
try {
fos = new FileOutputStream(file);
b.compress(CompressFormat.JPEG, 95, fos); // NullPointerException!
Toast.makeText(this, "The current view has been succesfully saved "
+ "as image.", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
Toast.makeText(this, "Unfortunatly an error occured and this "
+ "action failed.", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Bacause of lacking access to the storage "
+ "of this device, the current view couldn't be saved as an image.",
Toast.LENGTH_LONG).show();
}
}
The problem is according to LogCat that there occured a NullPointerException when trying to create the jpeg. So probably the method container.getDrawingCache() is not working. On the phone the file is generated. However with the size of 0 bytes and no visible image. I would appreciate any suggestions what I have to do in order to make it work as I want.
Try it -
public static Bitmap convertViewToBitmap(View view) {
Bitmap result = null;
try {
result = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
view.draw(new Canvas(result));
}catch(Exception e) {}
return result;
}
Try it -
view.setDrawingCacheEnabled(true);
Bitmap = bm = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
How can I take a screenshot of a selected area of phone-screen not by any program but from code?
Here is the code that allowed my screenshot to be stored on an SD card and used later for whatever your needs are:
First, you need to add a proper permission to save the file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
And this is the code (running in an 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
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();
}
}
And this is how you can open the recently generated image:
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);
}
If you want to use this on fragment view then use:
View v1 = getActivity().getWindow().getDecorView().getRootView();
instead of
View v1 = getWindow().getDecorView().getRootView();
on takeScreenshot() function
Note:
This solution doesn't work if your dialog contains a surface view. For details please check the answer to the following question:
Android Take Screenshot of Surface View Shows Black Screen
Call this method, passing in the outer most ViewGroup that you want a screen shot of:
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Note: works only for rooted phone
Programmatically, you can run adb shell /system/bin/screencap -p /sdcard/img.png as below
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
then read img.png as Bitmap and use as your wish.
No root permission or no big coding is required for this method.
On adb shell using below command you can take screen shot.
input keyevent 120
This command does not required any root permission so same you can perform from java code of android application also.
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
More about keyevent code in android see http://developer.android.com/reference/android/view/KeyEvent.html
Here we have used. KEYCODE_SYSRQ its value is 120 and used for System Request / Print Screen key.
As CJBS said, The output picture will be saved in /sdcard/Pictures/Screenshots
Mualig answer is very good, but I had the same problem Ewoks describes, I'm not getting the background. So sometimes is good enough and sometimes I get black text over black background (depending on the theme).
This solution is heavily based in Mualig code and the code I've found in Robotium. I'm discarding the use of drawing cache by calling directly to the draw method. Before that I'll try to get the background drawable from current activity to draw it first.
// Some constants
final static String SCREENSHOTS_LOCATIONS = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
// Get device dimmensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get root view
View view = mCurrentUrlMask.getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Activity activity = getCurrentActivity();
final Theme theme = activity.getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = activity.getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
// Save the screenshot to the file system
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS
+ System.currentTimeMillis() + ".jpg");
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d(LOGTAG, "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
As a reference, one way to capture the screen (and not just your app activity) is to capture the framebuffer (device /dev/graphics/fb0). To do this you must either have root privileges or your app must be an app with signature permissions ("A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission") - which is very unlikely unless you compiled your own ROM.
Each framebuffer capture, from a couple of devices I have tested, contained exactly one screenshot. People have reported it to contain more, I guess it depends on the frame/display size.
I tried to read the framebuffer continuously but it seems to return for a fixed amount of bytes read. In my case that is (3 410 432) bytes, which is enough to store a display frame of 854*480 RGBA (3 279 360 bytes). Yes, the frame, in binary, outputted from fb0 is RGBA in my device. This will most likely depend from device to device. This will be important for you to decode it =)
In my device /dev/graphics/fb0 permissions are so that only root and users from group graphics can read the fb0.
graphics is a restricted group so you will probably only access fb0 with a rooted phone using su command.
Android apps have the user id (uid) = app_## and group id (guid) = app_## .
adb shell has uid = shell and guid = shell, which has much more permissions than an app. You can actually check those permissions at /system/permissions/platform.xml
This means you will be able to read fb0 in the adb shell without root but you will not read it within the app without root.
Also, giving READ_FRAME_BUFFER and/or ACCESS_SURFACE_FLINGER permissions on AndroidManifest.xml will do nothing for a regular app because these will only work for 'signature' apps.
Also check this closed thread for more details.
private void captureScreen() {
View v = getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
try {
FileOutputStream fos = new FileOutputStream(new File(Environment
.getExternalStorageDirectory().toString(), "SCREEN"
+ System.currentTimeMillis() + ".png"));
bmp.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Add the permission in the manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
For Supporting Marshmallow or above versions, please add the below code in the activity onCreate method
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
My solution is:
public static Bitmap loadBitmapFromView(Context context, View v) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
v.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
v.draw(c);
return returnedBitmap;
}
and
public void takeScreen() {
Bitmap bitmap = ImageUtils.loadBitmapFromView(this, view); //get Bitmap from the view
String mPath = Environment.getExternalStorageDirectory() + File.separator + "screen_" + System.currentTimeMillis() + ".jpeg";
File imageFile = new File(mPath);
OutputStream fout = null;
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
fout.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fout.close();
}
}
Images are saved in the external storage folder.
You can try the following library:
http://code.google.com/p/android-screenshot-library/
Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
Based on the answer of #JustinMorris above and #NiravDangi here https://stackoverflow.com/a/8504958/2232148 we must take the background and foreground of a view and assemble them like this:
public static Bitmap takeScreenshot(View view, Bitmap.Config quality) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), quality);
Canvas canvas = new Canvas(bitmap);
Drawable backgroundDrawable = view.getBackground();
if (backgroundDrawable != null) {
backgroundDrawable.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
view.draw(canvas);
return bitmap;
}
The quality parameter takes a constant of Bitmap.Config, typically either Bitmap.Config.RGB_565 or Bitmap.Config.ARGB_8888.
public class ScreenShotActivity extends Activity{
private RelativeLayout relativeLayout;
private Bitmap myBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout)findViewById(R.id.relative1);
relativeLayout.post(new Runnable() {
public void run() {
//take screenshot
myBitmap = captureScreen(relativeLayout);
Toast.makeText(getApplicationContext(), "Screenshot captured..!", Toast.LENGTH_LONG).show();
try {
if(myBitmap!=null){
//save image to SD card
saveImage(myBitmap);
}
Toast.makeText(getApplicationContext(), "Screenshot saved..!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public static Bitmap captureScreen(View v) {
Bitmap screenshot = null;
try {
if(v!=null) {
screenshot = Bitmap.createBitmap(v.getMeasuredWidth(),v.getMeasuredHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(screenshot);
v.draw(canvas);
}
}catch (Exception e){
Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
}
return screenshot;
}
public static void saveImage(Bitmap bitmap) throws IOException{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes);
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
}
}
ADD PERMISSION
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
You can try to do something like this,
Getting a bitmap cache from a layout or a view by doing something like
First you gotta setDrawingCacheEnabled to a layout(a linearlayout or relativelayout, or a view)
then
Bitmap bm = layout.getDrawingCache()
Then you do whatever you want with the bitmap. Either turning it into an image file, or send the bitmap's uri to somewhere else.
Short way is
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Most of the answers for this question use the the Canvas drawing method or drawing cache method. However, the View.setDrawingCache() method is deprecated in API 28. Currently the recommended API for making screenshots is the PixelCopy class available from API 24 (but the methods which accept Window parameter are available from API 26 == Android 8.0 Oreo). Here is a sample Kotlin code for retrieving a Bitmap:
#RequiresApi(Build.VERSION_CODES.O)
fun saveScreenshot(view: View) {
val window = (view.context as Activity).window
if (window != null) {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
saveBitmap(bitmap)
}
// possible to handle other result codes ...
}, Handler())
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
}
}
}
For those who want to capture a GLSurfaceView, the getDrawingCache or drawing to canvas method won't work.
You have to read the content of the OpenGL framebuffer after the frame has been rendered. There is a good answer here
I have created a simple library that takes a screenshot from a View and either gives you a Bitmap object or saves it directly to any path you want
https://github.com/abdallahalaraby/Blink
If you want to take screenshot from fragment than follow this:
Override onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_one, container, false);
mView = view;
}
Logic for taking screenshot:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View view = mView.findViewById(R.id.scrollView1);
shareScreenShotM(view, (NestedScrollView) view);
}
method shareScreenShotM)():
public void shareScreenShotM(View view, NestedScrollView scrollView){
bm = takeScreenShot(view,scrollView); //method to take screenshot
File file = savePic(bm); // method to save screenshot in phone.
}
method takeScreenShot():
public Bitmap takeScreenShot(View u, NestedScrollView z){
u.setDrawingCacheEnabled(true);
int totalHeight = z.getChildAt(0).getHeight();
int totalWidth = z.getChildAt(0).getWidth();
Log.d("yoheight",""+ totalHeight);
Log.d("yowidth",""+ totalWidth);
u.layout(0, 0, totalWidth, totalHeight);
u.buildDrawingCache();
Bitmap b = Bitmap.createBitmap(u.getDrawingCache());
u.setDrawingCacheEnabled(false);
u.destroyDrawingCache();
return b;
}
method savePic():
public static File savePic(Bitmap bm){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + "/Foldername");
if (!sdCardDirectory.exists()) {
sdCardDirectory.mkdirs();
}
// File file = new File(dir, fileName);
try {
file = new File(sdCardDirectory, Calendar.getInstance()
.getTimeInMillis() + ".jpg");
file.createNewFile();
new FileOutputStream(file).write(bytes.toByteArray());
Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath());
Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
For activity you can simply use View v1 = getWindow().getDecorView().getRootView(); instead of mView
Just extending taraloca's answer. You must add followings lines to make it work. I have made the image name static. Please ensure you use taraloca's timestamp variable incase you need dynamic image name.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private void verifyStoragePermissions() {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}else{
takeScreenshot();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_STORAGE) {
takeScreenshot();
}
}
}
And in the AndroidManifest.xml file following entries are must:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For Full Page Scrolling Screenshot
If you want to capture a full View screenshot (Which contains a scrollview or so) then have a check at this library
https://github.com/peter1492/LongScreenshot
All you have to do is import the Gradel, and create an object of BigScreenshot
BigScreenshot longScreenshot = new BigScreenshot(this, x, y);
A callback will be received with the bitmap of the Screenshots taken while automatically scrolling through the screen view group and at the end assembled together.
#Override public void getScreenshot(Bitmap bitmap) {}
Which can be saved to the gallery or whatsoever usage is necessary their after
For system applications only!
Process process;
process = Runtime.getRuntime().exec("screencap -p " + outputPath);
process.waitFor();
Note: System applications don't need to run "su" to execute this command.
The parameter view is the root layout object.
public static Bitmap screenShot(View view) {
Bitmap bitmap = null;
if (view.getWidth() > 0 && view.getHeight() > 0) {
bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
}
return bitmap;
}
From Android 11 (API level 30) you can take screen shot with the accessibility service:
takeScreenshot - Takes a screenshot of the specified display and returns it via an AccessibilityService.ScreenshotResult.
Take screenshot of a view in android.
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
If you want to capture screenshot of a View, use View::drawToBitmap extension function:
val bitmap = myTargetView.drawToBitmap(/*Optional:*/ Bitmap.Config.ARGB_8888)
Only make sure to use the -ktx version of AndroidX Core library:
implementation("androidx.core:core-ktx:1.6.0")
I've already answered a similar question like this here.
Kotlin
private fun screenShot() {
try {
val mPath: String = this.getExternalFilesDir(null).getAbsolutePath()
.toString() + "/temp" + ".png"
// create bitmap screenshot
val v1: View = getWindow().getDecorView().getRootView()
v1.isDrawingCacheEnabled = true
val bitmap = Bitmap.createBitmap(v1.drawingCache)
v1.isDrawingCacheEnabled = false
val imageFile = File(mPath)
val outputStream = FileOutputStream(imageFile)
val quality = 100
bitmap.compress(Bitmap.CompressFormat.PNG, quality, outputStream)
outputStream.flush()
outputStream.close()
//or you can share to test the method fast
val uriPath =
FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile)
val intent = Intent(Intent.ACTION_SEND)
intent.type = "image/*"
intent.clipData = ClipData.newRawUri("", uriPath)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
intent.putExtra(Intent.EXTRA_STREAM, uriPath)
startActivity(Intent.createChooser(intent, "Sharing to..."))
} catch (e: Throwable) {
e.printStackTrace()
}
}
Java
private void screenShot() {
try {
String mPath = this.getExternalFilesDir(null).getAbsolutePath().toString() + "/temp" + ".png";
// create bitmap screenshot
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.PNG, quality, outputStream);
outputStream.flush();
outputStream.close();
//or you can share to test the method fast
Uri uriPath = FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.setClipData(ClipData.newRawUri("", uriPath));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, uriPath);
startActivity(Intent.createChooser(intent, "Sharing to..."));
} catch (Throwable e) {
e.printStackTrace();
}
}
If you want to capture a view or layout like RelativeLayout or LinearLayout etc.
Just use the code:
LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);
now you can save this bitmap on device storage by :
FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
outStream = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
addImageGallery(file);
//mail.setEnabled(true);
flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
outStream.flush();
outStream.close();
} catch (IOException e) {e.printStackTrace();}