Ответ 1
В соответствии с эта ссылка, можно использовать ddms в каталоге tools android sdk для захвата экрана.
Для этого в приложении (а не во время разработки) есть приложения для этого. Но, как указывает @zed_0xff, он, безусловно, требует root.
Возможный дубликат:
Как программно сделать снимок экрана на Android?
Как захватить содержимое экрана устройства Android и сделать файл изображения с использованием данных моментальных снимков? Какой API я должен использовать или где я могу найти связанные ресурсы?
BTW: не снимок камеры, но экран устройства
В соответствии с эта ссылка, можно использовать ddms в каталоге tools android sdk для захвата экрана.
Для этого в приложении (а не во время разработки) есть приложения для этого. Но, как указывает @zed_0xff, он, безусловно, требует root.
Используйте следующий код:
Bitmap bitmap;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
Здесь MyView
- это View
, через которое нам нужно включить в экран. Вы также можете получить DrawingCache
из любого View
таким образом (без getRootView()
).
Есть и другой способ.
Если у нас есть ScrollView
как корневой вид, то лучше использовать следующий код,
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout id)
root.setDrawingCacheEnabled(false);
Вот метод getBitmapFromView()
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view background
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
Он отобразит весь экран, включая контент, скрытый в вашем ScrollView
ОБНОВЛЕНО ОТ 20-04-2016
Существует еще один лучший способ сделать снимок экрана.
Здесь я сделал снимок экрана WebView
.
WebView w = new WebView(this);
w.setWebViewClient(new WebViewClient()
{
public void onPageFinished(final WebView webView, String url) {
new Handler().postDelayed(new Runnable(){
@Override
public void run() {
webView.measure(View.MeasureSpec.makeMeasureSpec(
View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
webView.layout(0, 0, webView.getMeasuredWidth(),
webView.getMeasuredHeight());
webView.setDrawingCacheEnabled(true);
webView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(),
webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
int height = bitmap.getHeight();
canvas.drawBitmap(bitmap, 0, height, paint);
webView.draw(canvas);
if (bitmap != null) {
try {
String filePath = Environment.getExternalStorageDirectory()
.toString();
OutputStream out = null;
File file = new File(filePath, "/webviewScreenShot.png");
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 50, out);
out.flush();
out.close();
bitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, 1000);
}
});
Надеюсь, это поможет..!
AFAIK. Все методы, используемые для захвата скриншота Android, используют фреймбуфер /dev/graphics/fb 0. Это включает в себя ddms. Это требует, чтобы корень читался из этого потока. ddms использует adbd для запроса информации, поэтому root не требуется, поскольку adb имеет разрешения, необходимые для запроса данных из /dev/graphics/fb 0.
Фреймбуфер содержит 2 + "кадры" изображений RGB565. Если вы можете прочитать данные, вам нужно знать разрешение экрана, чтобы узнать, сколько байтов необходимо для получения изображения. каждый пиксель составляет 2 байта, поэтому, если разрешение экрана было 480x800, вам нужно было бы прочитать 768 000 байт для изображения, так как изображение 480x800 RGB565 имеет 384 000 пикселей.
Для новых платформ Android можно выполнить системную утилиту screencap в /system/bin, чтобы получить скриншот без разрешения root. Вы можете попробовать "/system/bin/screencap -h", чтобы узнать, как использовать его в adb или любой оболочке.
Кстати, я думаю, что этот метод хорош только для одного моментального снимка. Если мы хотим захватить несколько кадров для воспроизведения экрана, это будет слишком медленно. Я не знаю, существует ли какой-либо другой подход для более быстрого захвата экрана.
[На основе исходного кода Android:]
На стороне С++ SurfaceFlinger реализует API captureScreen. Это отображается через интерфейс IPC связующего, каждый раз возвращая новую область золы, которая содержит необработанные пиксели с экрана. Фактический снимок экрана выполняется через OpenGL.
Для системных клиентов С++ интерфейс отображается через класс ScreenshotClient, определенный в <surfaceflinger_client/SurfaceComposerClient.h>
для Android < 4,1; для Android > 4.1 использовать <gui/SurfaceComposerClient.h>
До JB, чтобы сделать снимок экрана в программе на С++, этого было достаточно:
ScreenshotClient ssc;
ssc.update();
С JB и несколькими дисплеями он становится немного сложнее:
ssc.update(
android::SurfaceComposerClient::getBuiltInDisplay(
android::ISurfaceComposer::eDisplayIdMain));
Затем вы можете получить к нему доступ:
do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);
Используя исходный код Android, вы можете скомпилировать свою собственную общую библиотеку для доступа к этому API, а затем выставить ее через JNI на Java. Чтобы создать снимок экрана из вашего приложения, приложение должно иметь разрешение READ_FRAME_BUFFER
.
Но даже тогда, по-видимому, вы можете создавать снимки экрана только из системных приложений, то есть тех, которые подписаны с тем же ключом, что и система. (Эта часть я до сих пор не совсем понимаю, так как я недостаточно хорошо знаком с системой Android Permissions.)
Вот фрагмент кода для JB 4.1/4.2:
#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/MemoryHeapBase.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
static void do_save(const char *filename, const void *buf, size_t size) {
int out = open(filename, O_RDWR|O_CREAT, 0666);
int len = write(out, buf, size);
printf("Wrote %d bytes to out.\n", len);
close(out);
}
int main(int ac, char **av) {
android::ScreenshotClient ssc;
const void *pixels;
size_t size;
int buffer_index;
if(ssc.update(
android::SurfaceComposerClient::getBuiltInDisplay(
android::ISurfaceComposer::eDisplayIdMain)) != NO_ERROR ){
printf("Captured: w=%d, h=%d, format=%d\n");
ssc.getWidth(), ssc.getHeight(), ssc.getFormat());
size = ssc.getSize();
do_save(av[1], pixels, size);
}
else
printf(" screen shot client Captured Failed");
return 0;
}
Вы можете попробовать следующую библиотеку: http://code.google.com/p/android-screenshot-library/ Android Screenshot Library (ASL) позволяет программно снимать скриншоты с устройств Android без необходимости иметь права доступа root. Вместо этого ASL использует собственный сервис, работающий в фоновом режиме, который запускается через Android Debug Bridge (ADB) один раз за загрузку устройства.
если вы хотите сделать захват экрана из кода Java в приложении Android AFAIK, у вас должны быть корневые резервные копии.
Framebuffer, похоже, подходит, он не всегда будет содержать 2+ фрейма, как упоминалось Райаном Конрадом. В моем случае он содержал только один. Я думаю, это зависит от размера рамки/дисплея.
Я пытался непрерывно читать фреймбуфер, но, похоже, он возвращается для фиксированного количества прочитанных байтов. В моем случае это (3 410 432) байт, что достаточно для хранения кадра отображения 854 * 480 RGBA (3 279 360 байт). Да, кадр в двоичном формате, выводимый из fb0, - это RGBA на моем устройстве. Это скорее всего будет зависеть от устройства к устройству. Это будет важно для вас, чтобы расшифровать его =)
В моих разрешениях device/dev/graphics/fb0 так, что только root, а пользователи из групповой графики могут читать fb0. графика - это ограниченная группа, поэтому вы, вероятно, будете иметь доступ только к fb0 с помощью корневого телефона с помощью команды su.
Android-приложения имеют идентификатор пользователя (uid) app _ ## и группу id (guid) app _ ##.
adb shell имеет uid shell и оболочку guid, которая имеет гораздо больше разрешений, чем приложение. Фактически вы можете проверить эти разрешения на уровне /system/permissions/platform.xml
Это означает, что вы сможете читать fb0 в оболочке adb без root, но вы не будете читать его в приложении без root.
Кроме того, предоставление разрешений READ_FRAME_BUFFER и/или ACCESS_SURFACE_FLINGER для AndroidManifest.xml ничего не сделает для обычного приложения, потому что они будут работать только для приложений подписи.