I've reversed engineered the jar file from AndroidProjector. I am trying to modify AndroidProjector to accomodate different screen sizes and I am running into problems with org.eclipse.swt.graphics.ImageData.blit() - ArrayOutOfBoundsException.
The project also uses this file (RawData) as part of the solution.
My Android Projector call:
private void getFramebufferHeader(SocketChannel paramSocketChannel)
throws IOException
{
ByteBuffer localByteBuffer = ByteBuffer.wrap(new byte[4]);
readAdbChannel(paramSocketChannel, localByteBuffer);
localByteBuffer.rewind();
localByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
int i = localByteBuffer.getInt();
int j = RawImage.getHeaderSize(i);
localByteBuffer = ByteBuffer.wrap(new byte[j * 4]);
readAdbChannel(paramSocketChannel, localByteBuffer);
localByteBuffer.rewind();
localByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
this.mRawImage = new RawImage();
this.mRawImage.readHeader(i, localByteBuffer,percentSize);
}
ArrayOutOfBounds Exception Here:
private void updateDeviceImage(Shell paramShell, RawImage paramRawImage)
{
PaletteData localPaletteData = new PaletteData(paramRawImage.getRedMask(), paramRawImage.getGreenMask(), paramRawImage.getBlueMask());
//paramRawImage.getRedMask() = -16777216
//paramRawImage.getRedMask() = 16711680
//paramRawImage.getBlueMask() = 65289
ImageData localImageData = null;
//ArrayOutOfBounds Exception Here////////////////
//paramRawImage.width = 800
//paramRawImage.height = 1280
//paramRawImage.bpp = 32
//
localImageData = new ImageData(paramRawImage.width, paramRawImage.height, paramRawImage.bpp, localPaletteData, 1, paramRawImage.data);
Image localImage = new Image(paramShell.getDisplay(), localImageData);
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/////////////////////////////////////////
this.mImageLabel.setImage(localImage);
this.mImageLabel.pack();
paramShell.pack();
}
My modified RawData method call (the outofbounds exception occurs when percentSize is less than 100):
public boolean readHeader(int version, ByteBuffer buf, int percentSize) {
this.version = version;
if (version == 16) {
// compatibility mode with original protocol
this.bpp = 16;
// read actual values.
this.size = buf.getInt() * percentSize/100;
this.width = buf.getInt() * percentSize/100;
this.height = buf.getInt() * percentSize/100;
// create default values for the rest. Format is 565
this.red_offset = 11 * percentSize/100;
this.red_length = 5 * percentSize/100;
this.green_offset = 5 * percentSize/100;
this.green_length = 6 * percentSize/100;
this.blue_offset = 0 ;
this.blue_length = 5 * percentSize/100;
this.alpha_offset = 0;
this.alpha_length = 0;
} else if (version == 1) {
this.bpp = buf.getInt();
this.size = buf.getInt() * percentSize/100;
this.width = buf.getInt() * percentSize/100;
this.height = buf.getInt() * percentSize/100;
if (percentSize < 100) {
this.red_offset = 11;
this.red_length = 5;
this.green_offset = 5;
this.green_length = 6;
this.blue_offset = buf.getInt() ;
this.blue_length = 5;
this.alpha_offset = buf.getInt();
this.alpha_length = buf.getInt();
} else {
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;
}
Here is my exception:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 16390
at org.eclipse.swt.graphics.ImageData.blit(Unknown Source)
at org.eclipse.swt.graphics.Image.init(Unknown Source)
at org.eclipse.swt.graphics.Image.init(Unknown Source)
at org.eclipse.swt.graphics.Image.<init>(Unknown Source)
at com.google.android.AndroidProjector.updateDeviceImage(AndroidProjector.java:262)
at com.google.android.AndroidProjector.open(AndroidProjector.java:56)
at com.google.android.AndroidProjector.main(AndroidProjector.java:273)
I was really barking up the wrong tree with my approach. After much googling, instead of messing with the RawImage, I recreated the shell size and the resized the image.
My code now lives here:
https://github.com/techartist/AndroidProjector
private void open()
throws IOException
{
Display.setAppName("Android Projector");
Display localDisplay = new Display();
final Shell localShell = new Shell(localDisplay);
localShell.setText("Device Screen");
localShell.setSize(width,height);
//localShell.setLocation(300, 300);
createContents(localShell);
localShell.addShellListener(new ShellListener() {
public void shellIconified(ShellEvent e) {
}
public void shellDeiconified(ShellEvent e) {
}
public void shellDeactivated(ShellEvent e) {
}
public void shellClosed(ShellEvent e) {
System.out.println("Client Area: " + localShell.getClientArea());
}
public void shellActivated(ShellEvent e) {
int frameX = localShell.getSize().x - localShell.getClientArea().width;
int frameY = localShell.getSize().y - localShell.getClientArea().height;
if (AndroidProjector.this.mRotateImage) {
localShell.setSize(height * percentSize/100 + frameX, width * percentSize/100 + frameY);
}
else {
localShell.setSize(width * percentSize/100 + frameY,height * percentSize/100);
}
}
});
localShell.open();
SocketChannel localSocketChannel = null;
try
{
while (!localShell.isDisposed()) {
if (!localDisplay.readAndDispatch())
{
localSocketChannel = connectAdbDevice();
if (localSocketChannel == null) {
break;
}
if (startFramebufferRequest(localSocketChannel))
{
int frameX = localShell.getSize().x - localShell.getClientArea().width;
int frameY = localShell.getSize().y - localShell.getClientArea().height;
getFramebufferData(localSocketChannel);
updateDeviceImage(localShell, this.mRotateImage ? this.mRawImage.getRotated() : this.mRawImage);
if (this.mRotateImage) {
localShell.setSize(height * percentSize/100 + frameX, width * percentSize/100 + frameY);
}
else {
localShell.setSize(width * percentSize/100 + frameX, height * percentSize/100 + frameY);
}
}
localSocketChannel.close();
}
}
}
finally
{
if (localSocketChannel != null) {
localSocketChannel.close();
}
localDisplay.dispose();
}
}
and then I resized the image on the fly:
private void updateDeviceImage(Shell paramShell, RawImage paramRawImage)
{
PaletteData localPaletteData = new PaletteData(paramRawImage.getRedMask(), paramRawImage.getGreenMask(), paramRawImage.getBlueMask());
ImageData localImageData = null;
localImageData = new ImageData(paramRawImage.width, paramRawImage.height, paramRawImage.bpp, localPaletteData, 1, paramRawImage.data);
try {
Image localImage = new Image(paramShell.getDisplay(), localImageData);
if (this.mRotateImage) {
localImage = resize(localImage,heightImage * percentSize/100 ,widthImage * percentSize/100);
} else {
localImage = resize(localImage,widthImage * percentSize/100,heightImage * percentSize/100);
}
this.mImageLabel.setImage(localImage);
this.mImageLabel.pack();
paramShell.pack();
} catch (Exception e) {
String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
//System.out.print(e.toString());
System.out.print(fullStackTrace);
//
}
}
and
private Image resize(Image image, int width, int height) {
Image scaled = new Image(Display.getDefault(), width, height);
GC gc = new GC(scaled);
gc.setAntialias(SWT.ON);
gc.setInterpolation(SWT.HIGH);
gc.drawImage(image, 0, 0, image.getBounds().width, image.getBounds().height,
0, 0, width, height);
gc.dispose();
image.dispose(); // don't forget about me!
return scaled;
}
}