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?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Avadhani Y
  • 7,566
  • 19
  • 63
  • 90
  • 10
    It would freak me out if this is even possible. Apps doing this raises serious security concerns. – Blake Caldwell Nov 25 '13 at 03:50
  • 1
    **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. – Sherif elKhatib Nov 25 '13 at 07:49
  • 2
    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. – Justin Smith Nov 28 '13 at 18:28
  • **https://stackoverflow.com/a/54779181/7074112 Check this answer for a possible solution** – Peter Feb 20 '19 at 05:09

4 Answers4

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/

Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Viswanath Lekshmanan
  • 9,945
  • 1
  • 40
  • 64
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;
    }

}
swiftBoy
  • 35,607
  • 26
  • 136
  • 135
  • 2
    Wouldn't this only work if the application were in the foreground? – Justin Smith Nov 28 '13 at 18:34
  • 2
    `new BitmapDrawable(bitmap)` constructor is deprecated. Instead use `image.setImageBitmap(bm)` – Darpan May 29 '15 at 22:59
  • 2
    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. – shift66 Mar 14 '18 at 13:10
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.

Robin
  • 10,052
  • 6
  • 31
  • 52
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)

snachmsm
  • 17,866
  • 3
  • 32
  • 74