From 4eaf2b3df2a3cdfd0ef21a51fad10ca5f584b7f1 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 15 Sep 2009 20:09:08 -0700 Subject: Add support for new framebuffer protocol over adb. This is backward compatible with the original protocol. Change-Id: I93e811cb7775a10af82e70f31ae66d4cd74636b5 --- .../ddmlib/src/com/android/ddmlib/AdbHelper.java | 29 ++++- .../ddmlib/src/com/android/ddmlib/RawImage.java | 123 ++++++++++++++++++++- .../src/com/android/ddmuilib/ScreenShotDialog.java | 20 +++- 3 files changed, 158 insertions(+), 14 deletions(-) (limited to 'ddms/libs') diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java index 7a4d0ad..ce8d366 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java @@ -286,7 +286,8 @@ final class AdbHelper { return null; } - reply = new byte[16]; + // first the protocol version. + reply = new byte[4]; if (read(adbChan, reply) == false) { Log.w("ddms", "got partial reply from ADB fb:"); Log.hexDump("ddms", LogLevel.WARN, reply, 0, reply.length); @@ -296,10 +297,27 @@ final class AdbHelper { ByteBuffer buf = ByteBuffer.wrap(reply); buf.order(ByteOrder.LITTLE_ENDIAN); - imageParams.bpp = buf.getInt(); - imageParams.size = buf.getInt(); - imageParams.width = buf.getInt(); - imageParams.height = buf.getInt(); + int version = buf.getInt(); + + // get the header size (this is a count of int) + int headerSize = RawImage.getHeaderSize(version); + + // read the header + reply = new byte[headerSize * 4]; + if (read(adbChan, reply) == false) { + Log.w("ddms", "got partial reply from ADB fb:"); + Log.hexDump("ddms", LogLevel.WARN, reply, 0, reply.length); + adbChan.close(); + return null; + } + buf = ByteBuffer.wrap(reply); + buf.order(ByteOrder.LITTLE_ENDIAN); + + // fill the RawImage with the header + if (imageParams.readHeader(version, buf) == false) { + Log.e("Screenshot", "Unsupported protocol: " + version); + return null; + } Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size=" + imageParams.size + ", width=" + imageParams.width @@ -314,6 +332,7 @@ final class AdbHelper { adbChan.close(); return null; } + imageParams.data = reply; } finally { if (adbChan != null) { diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/RawImage.java b/ddms/libs/ddmlib/src/com/android/ddmlib/RawImage.java index 610cb59..e3d4e09 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/RawImage.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/RawImage.java @@ -16,17 +16,134 @@ package com.android.ddmlib; +import java.nio.ByteBuffer; + /** * Data representing an image taken from a device frame buffer. */ public final class RawImage { - /** - * bit-per-pixel value. - */ + public int version; public int bpp; public int size; public int width; public int height; + public int red_offset; + public int red_length; + public int blue_offset; + public int blue_length; + public int green_offset; + public int green_length; + public int alpha_offset; + public int alpha_length; public byte[] data; + + /** + * Reads the header of a RawImage from a {@link ByteBuffer}. + *

The way the data is sent over adb is defined in system/core/adb/framebuffer_service.c + * @param version the version of the protocol. + * @param buf the buffer to read from. + * @return true if success + */ + public boolean readHeader(int version, ByteBuffer buf) { + this.version = version; + + if (version == 16) { + // compatibility mode with original protocol + this.bpp = 16; + + // read actual values. + this.size = buf.getInt(); + this.width = buf.getInt(); + this.height = buf.getInt(); + + // create default values for the rest. Format is 565 + this.red_offset = 11; + this.red_length = 5; + this.green_offset = 5; + this.green_length = 6; + this.blue_offset = 0; + this.blue_length = 5; + this.alpha_offset = 0; + this.alpha_length = 0; + } else if (version == 1) { + this.bpp = buf.getInt(); + this.size = buf.getInt(); + this.width = buf.getInt(); + this.height = buf.getInt(); + this.red_offset = buf.getInt(); + this.red_length = buf.getInt(); + this.blue_offset = buf.getInt(); + this.blue_length = buf.getInt(); + this.green_offset = buf.getInt(); + this.green_length = buf.getInt(); + this.alpha_offset = buf.getInt(); + this.alpha_length = buf.getInt(); + } else { + // unsupported protocol! + return false; + } + + return true; + } + + /** + * Returns the mask value for the red color. + *

This value is compatible with org.eclipse.swt.graphics.PaletteData + */ + public int getRedMask() { + return getMask(red_length, red_offset); + } + + /** + * Returns the mask value for the green color. + *

This value is compatible with org.eclipse.swt.graphics.PaletteData + */ + public int getGreenMask() { + return getMask(green_length, green_offset); + } + + /** + * Returns the mask value for the blue color. + *

This value is compatible with org.eclipse.swt.graphics.PaletteData + */ + public int getBlueMask() { + return getMask(blue_length, blue_offset); + } + + /** + * Returns the size of the header for a specific version of the framebuffer adb protocol. + * @param version the version of the protocol + * @return the number of int that makes up the header. + */ + public static int getHeaderSize(int version) { + switch (version) { + case 16: // compatibility mode + return 3; // size, width, height + case 1: + return 12; // bpp, size, width, height, 4*(length, offset) + } + + return 0; + } + + /** + * creates a mask value based on a length and offset. + *

This value is compatible with org.eclipse.swt.graphics.PaletteData + */ + private int getMask(int length, int offset) { + int res = 0; + for (int i = 0 ; i < length ; i++) { + res = (res << 1) + 1; + } + + res = res << offset; + + // if the bpp is 32 bits then we need to invert it because the buffer is in little endian + if (bpp == 32) { + return Integer.reverseBytes(res); + } + + return res; + } } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java index b0200fa..778c594 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java @@ -165,7 +165,8 @@ public class ScreenShotDialog extends Dialog { Image image = getDeviceImage(); if (image == null) { Display display = shell.getDisplay(); - image = ImageHelper.createPlaceHolderArt(display, 320, 240, display.getSystemColor(SWT.COLOR_BLUE)); + image = ImageHelper.createPlaceHolderArt( + display, 320, 240, display.getSystemColor(SWT.COLOR_BLUE)); mSave.setEnabled(false); mBusyLabel.setText("Screen not available"); } else { @@ -199,15 +200,22 @@ public class ScreenShotDialog extends Dialog { if (rawImage == null) return null; - // convert raw data to an Image - assert rawImage.bpp == 16; - PaletteData palette = new PaletteData(0xf800, 0x07e0, 0x001f); + // convert raw data to an Image. + PaletteData palette = new PaletteData( + rawImage.getRedMask(), + rawImage.getGreenMask(), + rawImage.getBlueMask()); ImageData imageData = new ImageData(rawImage.width, rawImage.height, - rawImage.bpp, palette, 1, rawImage.data); + rawImage.bpp, palette, 1, rawImage.data); - return new Image(getParent().getDisplay(), imageData); + if (imageData != null) { + return new Image(getParent().getDisplay(), imageData); + } + + return null; } + /* * Prompt the user to save the image to disk. */ -- cgit v1.1