9

更新Androidでスクリーンショットを取得する方法を尋ねる投稿は他にもたくさんありますが、その方法について完全な答えを持っているものはないようです。もともと、フレームバッファへのストリームを開こうとしたときに遭遇した特定の問題のために、これを質問として投稿しました。これで、フレームバッファをファイルにダンプするように切り替えたので、投稿を更新して、そこに到達した方法を示しました。参考までに(そして確認のために)、この投稿からファイルにFrameBufferを送信するコマンドを見つけました(残念ながら、彼はその時点に到達する方法を提供していませんでした)。フレームバッファから取得した生データを実際の画像ファイルに変換する方法がありません。

私の意図は、Androidデバイスの実際の画面の完全なダンプを取ることでした。adbブリッジを使用せずにこれを行うことができる唯一の方法は、システムのフレームバッファーに直接アクセスすることでした。明らかに、このアプローチには、デバイスとそれを実行するアプリに対するroot権限が必要です。幸いなことに、私の目的では、デバイスのセットアップ方法を制御でき、アプリケーションに提供されたルート権限でデバイスをルート化することが可能です。私のテストは現在、2.2.3を実行している古いDroidで行われています。

https://stackoverflow.com/a/6970338/1446554からアプローチする方法の最初のヒントを見つけました。もう少し調査した後、rootとしてシェルコマンドを適切に実行する方法を説明する別の記事を見つけました。彼らはそれを使って再起動を実行していました。私はそれを使って現在のフレームバッファを実際のファイルに送信します。私の現在のテストは、ADBを介して基本的なアクティビティ(それぞれルートが提供されている)でこれを行う場合にのみ取得されています。バックグラウンドで実行されているサービスからさらにテストを行います。アップデートが予定されています。現在の画面をファイルにエクスポートできるテストアクティビティ全体を次に示します。

public class ScreenshotterActivity extends Activity {
    public static final String TAG = "ScreenShotter";

    private Button _SSButton;
    private PullScreenAsyncTask _Puller;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        _SSButton = (Button)findViewById(R.id.main_screenshotButton);
        _SSButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                if (_Puller != null)
                    return;
                //TODO: Verify that external storage is available! Could always use internal instead...

                _Puller = new PullScreenAsyncTask();
                _Puller.execute((Void[])null);
            }
        });
    }

    private void runSuShellCommand(String cmd) {
        Runtime runtime = Runtime.getRuntime();
        Process proc = null;
        OutputStreamWriter osw = null;
        StringBuilder sbstdOut = new StringBuilder();
        StringBuilder sbstdErr = new StringBuilder();

        try { // Run Script
            proc = runtime.exec("su");
            osw = new OutputStreamWriter(proc.getOutputStream());
            osw.write(cmd);
            osw.flush();
            osw.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (osw != null) {
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();                    
                }
            }
        }

        try {
            if (proc != null)
                proc.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        sbstdOut.append(readBufferedReader(new InputStreamReader(proc.getInputStream())));
        sbstdErr.append(readBufferedReader(new InputStreamReader(proc.getErrorStream())));
    }

    private String readBufferedReader(InputStreamReader input) {

        BufferedReader reader = new BufferedReader(input);
        StringBuilder found = new StringBuilder();
        String currLine = null;
        String sep = System.getProperty("line.separator");
        try {
            // Read it all in, line by line.
            while ((currLine = reader.readLine()) != null) {
                found.append(currLine);
                found.append(sep);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    class PullScreenAsyncTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {

            File ssDir = new File(Environment.getExternalStorageDirectory(), "/screenshots");
            if (ssDir.exists() == false) {
                Log.i(TAG, "Screenshot directory doesn't already exist, creating...");
                if (ssDir.mkdirs() == false) {
                    //TODO: We're kinda screwed... what can be done?
                    Log.w(TAG, "Failed to create directory structure necessary to work with screenshots!");
                    return null;
                }
            }
            File ss = new File(ssDir, "ss.raw");            
            if (ss.exists() == true) {
                ss.delete();
                Log.i(TAG, "Deleted old Screenshot file.");
            }
            String cmd = "/system/bin/cat /dev/graphics/fb0 > "+ ss.getAbsolutePath();
            runSuShellCommand(cmd);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            _Puller = null;
        }
    }
}

android.permission.WRITE_EXTERNAL_STORAGEこれには、マニフェストに権限を追加する必要もあります。この投稿で提案されているように。それ以外の場合は、実行され、文句を言わず、ディレクトリもファイルも作成されません。

もともと、シェルコマンドを正しく実行する方法がわからなかったため、フレームバッファから使用可能なデータを取得できませんでした。コマンドを実行するためにストリームを使用するように切り替えたので、「>」を使用してフレームバッファの現在のデータを実際のファイルに送信できます...

4

3 に答える 3

10

プログラムで、次のように「adb shell /system/bin/screencap -p /sdcard/img.png」を実行できます。

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();
于 2013-03-04T18:24:19.273 に答える
5

ICS デバイスの簡単な解決策は、コマンド ラインから次のコマンドを使用することです。

adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png

これにより、screenshot.png ファイルが現在のディレクトリに保存されます。

4.0.3 を実行する Samsung Galaxy SII でテスト済み。

于 2012-08-03T15:44:24.107 に答える
3

それは、電話によって異なります。デバイスの基本的なグラフィック形式によって異なります。システムコールを使用して、グラフィックス形式をポーリングできます。グラフィック形式がわかっているデバイスでのみこれを実行する場合は、既知の形式に変換するコンバータを作成できます。

次のプロジェクトを見ることができます: http://code.google.com/p/android-fb2png/

fb2png.c のソース コードを見ると、デバイスが画面イメージをメモリに保存する方法に関する情報を含む FBIOGET_VSCREENINFO をポーリングしていることがわかります。それがわかれば、使用できる形式に変換できるはずです。

これが役立つことを願っています。

于 2012-07-19T11:29:24.403 に答える