Get screenshot of current foreground app on Android having root priviliges
Asked Answered
D

2

0

I'm developing an application that is installed on the system partition and I would like to know if it's possible to get a screenshot of the current foreground application from a service. Of course, the application being any third party app.

I'm not interested in security issues or anything related to that matter. I only want to get a snapshot of the current foreground third party app.

Note: I'm aware of the /system/bin/screencap solution but I'm looking for a more elegant alternative that does everything programmatically.

Deface answered 30/12, 2014 at 19:13 Comment(0)
D
1

Months have passed since I asked this question but just now had the time to add this feature. The way to do this is simply by calling screencap -p <file_name_absolute_path> and then grabbing the file. Next is the code I used:

private class WorkerTask extends AsyncTask<String, String, File> {
    @Override
    protected File doInBackground(String... params) {
        File screenshotFile = new File(Environment.getExternalStorageDirectory().getPath(), SCREENSHOT_FILE_NAME);
        try {
            Process screencap = Runtime.getRuntime().exec("screencap -p " + screenshotFile.getAbsolutePath());
            screencap.waitFor();
            return screenshotFile;
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(File screenshot_file) {
        // Do something with the file.
    }
}

Remember to add the <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> permission to the manifest. Otherwise screenshot.png will be blank.

This is much simpler than what Goran stated and is what I finally used.

Note: It only worked for me when the app is installed on the system partition.

Deface answered 15/12, 2015 at 11:48 Comment(2)
Does this require the phone to be rooted or plugged in via USB?Bristol
@Bristol I think it does require root but don't remember for sure. You could try it. It has nothing to do with the USB plug, though.Deface
J
2

The method that I'm going to describe below will let you to programmatically take screen shots of whatever app it's in the foreground from a background process.

I am assuming that you have a rooted device. I this case you can use the uiautomator framework to get the job done.

This framework has a been created to automate black box testing of apps on android, but it will suite this purpose as well. We are going to use the method

takeScreenshot(File storePath, float scale, int quality)

This goes in the service class:

File f = new File(context.getApplicationInfo().dataDir, "test.jar");

//this command will start uiautomator
String cmd = String.format("uiautomator runtest %s -c com.mypacket.Test", f.getAbsoluteFile());
Process p = doCmds(cmd);
if(null != p)
{
    p.waitFor();
}
else
{
    Log.e(TAG, "starting the test FAILED");
}

private Process doCmds(String cmds)
{
    try
    {
        Process su = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(su.getOutputStream());

        os.writeBytes(cmds + "\n");
        os.writeBytes("exit\n");
        os.flush();
        os.close();

        return su;
    }
    catch(Exception e)
    {
        e.printStackTrace();
        Log.e(TAG, "doCmds FAILED");

        return null;
    }
}

This is the class for uiautomator:

public class Test extends UiAutomatorTestCase
{
    public void testDemo()
    {
        UiDevice dev = UiDevice.getInstance();

        File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
        dev.takeScreenshot(f, 1.0, 100);
    }
}

It's best if you create a background thread in which uiautomator will run, that way it will not run onto the ui thread. (the Service runs on the ui thread).

uiatuomator doesn't know about or have a android context. Once uiautomator gets the control you will be able to call inside it android methods that do not take a context parameter or belong to the context class.

If you need to communicate between uiautomator and the service (or other android components) you can use LocalSocket. This will allow communication in both ways.

Jeaninejeanlouis answered 5/1, 2015 at 20:8 Comment(0)
D
1

Months have passed since I asked this question but just now had the time to add this feature. The way to do this is simply by calling screencap -p <file_name_absolute_path> and then grabbing the file. Next is the code I used:

private class WorkerTask extends AsyncTask<String, String, File> {
    @Override
    protected File doInBackground(String... params) {
        File screenshotFile = new File(Environment.getExternalStorageDirectory().getPath(), SCREENSHOT_FILE_NAME);
        try {
            Process screencap = Runtime.getRuntime().exec("screencap -p " + screenshotFile.getAbsolutePath());
            screencap.waitFor();
            return screenshotFile;
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(File screenshot_file) {
        // Do something with the file.
    }
}

Remember to add the <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> permission to the manifest. Otherwise screenshot.png will be blank.

This is much simpler than what Goran stated and is what I finally used.

Note: It only worked for me when the app is installed on the system partition.

Deface answered 15/12, 2015 at 11:48 Comment(2)
Does this require the phone to be rooted or plugged in via USB?Bristol
@Bristol I think it does require root but don't remember for sure. You could try it. It has nothing to do with the USB plug, though.Deface

© 2022 - 2024 — McMap. All rights reserved.