Получите скриншот текущего приложения переднего плана на Android с правами root

Я занимаюсь разработкой приложения, которое установлено в системном разделе, и я хотел бы знать, возможно ли получить снимок экрана текущего приложения переднего плана от службы. Конечно, это приложение любого стороннего приложения.

Я не интересуюсь вопросами безопасности или чем-то связанным с этим вопросом. Я только хочу получить снимок текущего стороннего приложения переднего плана.

Примечание: я знаю о /system/bin/screencap Решение, но я ищу более элегантную альтернативу, которая делает все программно.

2 ответа

Решение

Прошли месяцы с тех пор, как я задал этот вопрос, но только сейчас было время добавить эту функцию. Способ сделать это просто позвонив screencap -p <file_name_absolute_path> а затем захватывает файл. Далее приведен код, который я использовал:

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.
    }
}

Не забудьте добавить <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> разрешение на манифест. В противном случае screenshot.png будет пустым.

Это намного проще, чем то, что сказал Горан, и это то, что я наконец использовал.

Примечание: это работало только для меня, когда приложение установлено в системном разделе.

Метод, который я собираюсь описать ниже, позволит вам программно делать снимки экрана любого приложения, находящегося на переднем плане, из фонового процесса.

Я предполагаю, что у вас есть рутированное устройство. В этом случае вы можете использовать инфраструктуру uiautomator для выполнения работы.

Этот фреймворк был создан для автоматизации тестирования приложений на Android в "черном ящике", но он также подойдет и для этой цели. Мы собираемся использовать метод

takeScreenshot(File storePath, float scale, int quality)

Это идет в классе обслуживания:

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;
    }
}

Это класс для 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);
    }
}

Лучше всего, если вы создадите фоновый поток, в котором будет работать uiautomator, чтобы он не работал в потоке пользовательского интерфейса. (Служба работает в потоке пользовательского интерфейса).

uiatuomator не знает или имеет контекст Android. Как только uiautomator получит элемент управления, вы сможете вызывать внутри него методы Android, которые не принимают параметр контекста или принадлежат к классу контекста.

Если вам необходимо установить связь между uiautomator и службой (или другими компонентами Android), вы можете использовать LocalSocket. Это позволит общаться обоими способами.

Другие вопросы по тегам