Android - How to take screenshot programmatically
Asked Answered
H

4

16

I need to screenshots of Android device or emulator programmatically when my application is installed and running in the background for every 200 milliseconds and save the images in my computer. I have implemented this procedure using below code and works only when my application is in foreground. I want to take screenshots when my application is in background as well. Below is my code:

public static Bitmap takeScreenshot(Activity activity, int ResourceID) { 
    Random r = new Random();
    int iterator=r.nextInt();   
     String mPath = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
    View v1 = activity.getWindow().getDecorView().findViewById(ResourceID);
    v1.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    v1.layout(0, 0, v1.getMeasuredWidth(), v1.getMeasuredHeight()); 
    v1.setDrawingCacheEnabled(true);
    final Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
    Bitmap resultBitmap = Bitmap.createScaledBitmap(bitmap, 640, 480, false);
    v1.setDrawingCacheEnabled(false);
    File imageFile = new File(mPath);
    imageFile.mkdirs();
    imageFile = new File(imageFile+"/"+iterator+"_screenshot.png");
    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        resultBitmap.compress(CompressFormat.PNG, 100, bos);
        byte[] bitmapdata = bos.toByteArray();

        //write the bytes in file
        FileOutputStream fos = new FileOutputStream(imageFile);
        fos.write(bitmapdata);
        fos.flush();
        fos.close();    
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return bitmap;
    }  

How can I implement the functionality of Refresh and Save buttons of Screencapture in Devices -> DDMS programmatically? Can I achieve that?

Hygrometry answered 22/11, 2013 at 2:52 Comment(4)
It would freak me out if this is even possible. Apps doing this raises serious security concerns.Concern
This can not be done except if the phone is rooted (kitkat). As for the "serious security concerns", I think there are more serious security concerns somewhere else. It is not that of a big deal if app can request a permission to take a screenshot or so.Quill
This isn't a screenshot or so... It's a screenshot every 200ms. Essentially a 5 FPS video. This would easily capture everything done on the phone. Not arguing against doing it for my own use (making a video of an app) but giving a 3rd party app the permission to take screenshots would be a long rabbit hole to go down.Acre
https://mcmap.net/q/57395/-how-to-programmatically-take-a-screenshot-on-android Check this answer for a possible solutionLukey
M
17

If your phone is rooted try this

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 convert it jpg as follows

Bitmap screen = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+         
File.separator +"img.png");

//my code for saving
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    screen.compress(Bitmap.CompressFormat.JPEG, 15, bytes);

//you can create a new file name "test.jpg" in sdcard folder.

File f = new File(Environment.getExternalStorageDirectory()+ File.separator + "test.jpg");
            f.createNewFile();
//write the bytes in file
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
// remember close de FileOutput

    fo.close();

you have no access to the screen if your application is in background unless you are rooted, the code above can take the screenshot most effectively of any screen even if you are in background.

UPDATE

Google has a library with which you can take screenshot without rooting, I tried that, But iam sure that it will eat out the memory as soon as possible.

Try http://code.google.com/p/android-screenshot-library/

Miseno answered 25/11, 2013 at 3:54 Comment(8)
Screen capturing working in emulator but not in real device plseBoyles
Is your device rooted ?Miseno
no,when user lisk on list item plan to display detailview with share option for that we need to save that layout bitmap and then we need to sahre that file for that am implement its working in emulator with capture the screen and sendmail intent its sharing coming to real devise its not workingBoyles
Please post your piece of code as gist and share the linkMiseno
gist.github.com/anonymous/84d06ec6c2cc368a0627 please once check this captureScreen code.in emulators its workin am providing write_external_storage in user-permissions in manifest alsoBoyles
Could you check the mPath ? Did you get any exception (In catch)?Miseno
and when i take screen shots its coming white background as black in real device.not exactly looks like how the view is visibleBoyles
900ms to take a screenshot is insanely bad :SLeblanc
W
12

Here is the way to do it.

Android taking Screen shots through code

Result Output:

enter image description here

enter image description here

public class CaptureScreenShots extends Activity {
    LinearLayout L1;
    ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.screen_shots);
         L1 = (LinearLayout) findViewById(R.id.LinearLayout01);
            Button but = (Button) findViewById(R.id.munchscreen);
            but.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    View v1 = L1.getRootView();
                    v1.setDrawingCacheEnabled(true);
                    Bitmap bm = v1.getDrawingCache();
                    BitmapDrawable bitmapDrawable = new BitmapDrawable(bm);
                    image = (ImageView) findViewById(R.id.screenshots);
                    image.setBackgroundDrawable(bitmapDrawable);
                }
            });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.screen_shots, menu);
        return true;
    }

}
Wisnicki answered 22/11, 2013 at 4:16 Comment(3)
Wouldn't this only work if the application were in the foreground?Acre
new BitmapDrawable(bitmap) constructor is deprecated. Instead use image.setImageBitmap(bm)Heuristic
This won't work if there is a SurfaceView in view hierarchy because SurfaceView doesn't have drawing cache. You will see a black rectangle in your screenshot.Groos
I
4

Taking screen shot in the background (like ADB) requires groups=1003(graphics). Otherwise you can only get the screen shot of your own process. So you can only either do it on a rooted device, or do it by running ADB native program.

Native cpp code sample could be found at https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r2.3/cmds/screencap/

And if you want to do it in java code, you need to access the hidden API of Surface class:

/**
 * Like {@link #screenshot(int, int, int, int)} but includes all
 * Surfaces in the screenshot.
 *
 * @hide
 */
public static native Bitmap screenshot(int width, int height);

These two should be both OK since ICS release, for early release like GB, you can check out the native cpp code.

However, in some Android devices, the implementation of the media system and canvas etc. is not very good, thus, you cannot capture any video playback or any surface view content in this case.

Improvisation answered 25/11, 2013 at 3:35 Comment(1)
It should be noted this method was removed in Android 4.3 and up.Maine
E
0

you may consider mixing MediaProjection and AccessibilityService. First one takes screenshot with ease, second one runs all the time "above" all apps

Tutorial how to run AccessibilityService in CODELABS

Full source of above examle HERE

In THIS answer you can find pretty useful piece of code for Activity. Remember to set proper fully transparent Theme:

<style name="Theme.AppCompat.Translucent" parent="Theme.AppCompat.NoActionBar">
    <item name="android:background">#00000000</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowAnimationStyle">@null</item>
</style>

Then loop startActivity in your AccessibilityService as frequent as you need, or even better - use LocalBroadcastManager to inform Service that Activity took screenshot and finished (so Service can start this Activity again)

I've done something similar (for internal use only) + screenshots were analyzed with OCR to get text from them. Kinda parsing, when not-your-app somehow defend from AccesibilityService features (this type of Service is intended to help disabled people e.g. in text reading, usually have access to TextViews)

Enciso answered 3/10, 2018 at 13:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.