Ccna final exam - java, php, javascript, ios, cshap all in one. This is a collaboratively edited question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.
Sunday, April 22, 2012
How to capture the android device screen content?
How to capture the android device screen content and make an image file using the snapshot data?which api I should use or where to find related resource? thanks in advance!
According to this: http://www.mobilecrunch.com/2008/10/31/how-to-capture-the-screen-of-an-android-device/ you can use ddms in the tools directory of the android sdk to take screen captures.
If you want to do this from within your application and not during development, there are applications to do so, see Screenshot for an example. But as zed_0xff points out it certainly requires root.
AFAIK, All of the methods currently to capture a screenshot of android use the /dev/graphics/fb0 framebuffer. This includes ddms. It does require root to read from this stream. ddms uses adbd to request the information, so root is not required as adb has the permissions needed to request the data from /dev/graphics/fb0.
The framebuffer contains 2+ "frames" of RGB565 images. If you are able to read the data, you would have to know the screen resolution to know how many bytes are needed to get the image. each pixel is 2 bytes, so if the screen res was 480x800, you would have to read 768,000 bytes for the image, since a 480x800 RGB565 image has 384,000 pixels.
You can try the following library: http://code.google.com/p/android-screenshot-library/ Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
At the C++ side, the SurfaceFlinger implements the captureScreen API. This is exposed over the binder IPC interface, returning each time a new ashmem area that contains the raw pixels from the screen. The actual screenshot is taken through OpenGL.
For the system C++ clients, the interface is exposed through the ScreenshotClient class, defined in <surfaceflinger_client/SurfaceComposerClient.h>.
To take a screenshot in a C++ program, this should be enough:
Using the Android source code, you can compile your own shared library to access that API, and then expose it through JNI to Java. To create a screen shot form your app, the app has to have the READ_FRAME_BUFFER permission. But even then, apparently you can create screen shots only from system applications, i.e. ones that are signed with the same key as the system. (This part I still don't quite understand, since I'm not familiar enough with the Android Permissions system.)
Below is some bad sample code, which does not properly track when the Java-side objects are deleted. I'm still working on a more proper approach.
if (status != android::NO_ERROR) { LOGD("Failed."); return status; }
/* XXX: Let the scheduler to kick in. The actual screenshot is taken in a separate thread in the SurfaceFlinger, and it may take some tweaking to make sure it really runs. */ int sched_yield(void);
LOGD("Captured."); /* Step 2: Create a an SkBitmap out of it. */ if (skb) { LOGD("Forming a bitmap...");
SkBitmap::Config config = SkBitmap::kARGB_8888_Config; /* XXX */ skb->setConfig(config, width, height); /* XXX: The following is wrong. It should use SkPixelRef instead */ skb->setPixels((*heap)->getBase(), NULL); }
either connect to the ADB service and get the framebuffer (no root needed) , or directly access /dev/graphics/fb0 to read the screen content, as presented here: http://www.pocketmagic.net/?p=1473
According to this: http://www.mobilecrunch.com/2008/10/31/how-to-capture-the-screen-of-an-android-device/ you can use ddms in the tools directory of the android sdk to take screen captures.
ReplyDeleteIf you want to do this from within your application and not during development, there are applications to do so, see Screenshot for an example. But as zed_0xff points out it certainly requires root.
AFAIK, All of the methods currently to capture a screenshot of android use the /dev/graphics/fb0 framebuffer. This includes ddms. It does require root to read from this stream. ddms uses adbd to request the information, so root is not required as adb has the permissions needed to request the data from /dev/graphics/fb0.
ReplyDeleteThe framebuffer contains 2+ "frames" of RGB565 images. If you are able to read the data, you would have to know the screen resolution to know how many bytes are needed to get the image. each pixel is 2 bytes, so if the screen res was 480x800, you would have to read 768,000 bytes for the image, since a 480x800 RGB565 image has 384,000 pixels.
You can try the following library:
ReplyDeletehttp://code.google.com/p/android-screenshot-library/
Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
Use following code
ReplyDeleteBitmap bitmap;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
Here MyView is the View through which we need include in screen.
if you want to do screen capture from Java code in Android app AFAIK you must have Root provileges.
ReplyDelete[Based on Android 2.3.X source code:]
ReplyDeleteAt the C++ side, the SurfaceFlinger implements the captureScreen API. This is exposed over the binder IPC interface, returning each time a new ashmem area that contains the raw pixels from the screen. The actual screenshot is taken through OpenGL.
For the system C++ clients, the interface is exposed through the ScreenshotClient class, defined in <surfaceflinger_client/SurfaceComposerClient.h>.
To take a screenshot in a C++ program, this should be enough:
ScreenshotClient ssc;
ssc.update();
Then you can access it:
do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);
Using the Android source code, you can compile your own shared library to access that API, and then expose it through JNI to Java. To create a screen shot form your app, the app has to have the READ_FRAME_BUFFER permission.
But even then, apparently you can create screen shots only from system applications, i.e. ones that are signed with the same key as the system. (This part I still don't quite understand, since I'm not familiar enough with the Android Permissions system.)
Below is some bad sample code, which does not properly track when the Java-side objects are deleted. I'm still working on a more proper approach.
JNIEXPORT jobject JNICALL
Java_Screenshot_capture(JNIEnv *env, jclass cls,
jint reqWidth, jint reqHeight) {
/* XXX: Check for memory leaks */
SkBitmap *skb = new SkBitmap();
android::status_t status;
status = capture_screen(reqWidth, reqHeight, skb);
if (status != android::NO_ERROR) {
return NULL;
}
return GraphicsJNI::createBitmap(env, skb, true, NULL);
}
int
capture_screen(int reqWidth, int reqHeight, void *voidp) {
android::status_t status;
uint32_t width;
uint32_t height;
android::PixelFormat format;
SkBitmap *skb = (SkBitmap *)voidp;
static android::sp<android::IMemoryHeap> heap;
LOGD("Starting screen capture...");
/* Step 1: Acquire the screen shot. */
/* See SurfaceComposerClient.cpp */
android::sp<android::ISurfaceComposer>
cs(android::ComposerService::getComposerService());
if (cs == NULL) return android::FAILED_TRANSACTION;
*heap = 0;
status =
cs->captureScreen(0, heap, &width, &height,
&format, reqWidth, reqHeight);
if (status != android::NO_ERROR) {
LOGD("Failed.");
return status;
}
/* XXX: Let the scheduler to kick in. The actual screenshot
is taken in a separate thread in the SurfaceFlinger,
and it may take some tweaking to make sure it really runs. */
int sched_yield(void);
LOGD("Captured.");
/* Step 2: Create a an SkBitmap out of it. */
if (skb) {
LOGD("Forming a bitmap...");
SkBitmap::Config config = SkBitmap::kARGB_8888_Config; /* XXX */
skb->setConfig(config, width, height);
/* XXX: The following is wrong. It should use SkPixelRef instead */
skb->setPixels((*heap)->getBase(), NULL);
}
LOGD("SkBitmap formed: base=%p", (*heap)->getBase());
return status;
}
either connect to the ADB service and get the framebuffer (no root needed) , or directly access /dev/graphics/fb0 to read the screen content, as presented here: http://www.pocketmagic.net/?p=1473
ReplyDelete