Get screenshot of current foreground app on Android having root priviliges

江枫思渺然 提交于 2019-12-02 08:43:58

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!