UPDATE Ci sono un certo numero di altri post che chiedono come ottenere uno Screenshot in Android ma nessuno sembra avere una risposta completa su come farlo. Originariamente l'ho postato come una domanda a causa di un particolare problema che stavo incontrando mentre tentavo di aprire un flusso sul Frame Buffer. Ora mi sono scambiato per scaricare il Frame Buffer in un file, quindi ho aggiornato il mio post per mostrare come sono arrivato. Per riferimento (e riconoscimento), ho trovato il comando per inviare il FrameBuffer a un file da this post (sfortunatamente non ha fornito come è arrivato a quel punto). Mi manca solo come trasformare i dati grezzi che ho tirato da Frame Buffer in un vero e proprio file immagine.Android cattura screenshot sul dispositivo rooted
La mia intenzione era di fare un dump completo dello schermo attuale su un dispositivo Android. Il modo solo in cui ho potuto trovare di farlo senza usare il bridge adb era di accedere direttamente al Frame Buffer del sistema. Ovviamente questo approccio richiederà i privilegi di root sul dispositivo e per l'app che lo esegue! Fortunatamente per i miei scopi ho il controllo su come è configurato il Dispositivo e avere il dispositivo rootato con i privilegi di root forniti alla mia applicazione è fattibile. Il mio test è attualmente in corso su un vecchio Droid in esecuzione 2.2.3.
Ho trovato i miei primi suggerimenti su come accedervi da https://stackoverflow.com/a/6970338/1446554. Dopo un po 'di ricerche ho trovato un altro articolo che descrive come correttamente run shell commands as root. Lo stavano usando per eseguire un riavvio, lo uso per inviare il buffer del frame corrente a un file reale. Il mio attuale test è solo arrivato a fare questo tramite ADB e in un'attività di base (ognuno è fornito come root). Farò ulteriori test da un servizio in esecuzione in background, gli aggiornamenti a venire! Qui è tutta la mia attività di test in grado di esportare la schermata corrente in un file:
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;
}
}
}
Questo richiede anche l'aggiunta del android.permission.WRITE_EXTERNAL_STORAGE
permesso per il Manifesto. Come suggerito in this post. Altrimenti gira, non si lamenta, non crea le directory né il file.
In origine non è stato possibile ottenere dati utilizzabili dal buffer di frame a causa della mancata comprensione di come eseguire correttamente i comandi della shell. Ora che ho scambiato per utilizzare gli stream per l'esecuzione di comandi, posso usare '>' per inviare i dati correnti del Frame Buffer a un file reale ...
Grazie per la vostra codifica. Tuttavia, il file '.raw' potrebbe avere un problema. Ho provato ad aprire il file di immagine '.raw' con google picassa, ma ha detto che c'è una parte in cui Picassa non può leggere. Sai qual è il problema? Come posso ottenere un file immagine normale da esso? Grazie. –
@swk Questa non è una domanda semplice a cui rispondere. Le mie esigenze erano più nel regno di determinare le differenze tra le schermate in sequenza, quindi non ho ancora pienamente determinato come trasformarle in immagini! Suggerirei una ricerca approfondita del resto di Stack Overflow specificatamente per come trasformare i dati trovati in/dev/graphics/fb0 in un'immagine. – cgolden
@swk Hai trovato un modo per coprire il framebuffer in un file immagine ?? –