diff options
Diffstat (limited to 'apps/SdkController/SdkControllerMultitouch/src/com/android/tools/sdkcontroller/sdkcontrollermultitouch/SdkControllerMultitouchActivity.java')
-rw-r--r-- | apps/SdkController/SdkControllerMultitouch/src/com/android/tools/sdkcontroller/sdkcontrollermultitouch/SdkControllerMultitouchActivity.java | 210 |
1 files changed, 165 insertions, 45 deletions
diff --git a/apps/SdkController/SdkControllerMultitouch/src/com/android/tools/sdkcontroller/sdkcontrollermultitouch/SdkControllerMultitouchActivity.java b/apps/SdkController/SdkControllerMultitouch/src/com/android/tools/sdkcontroller/sdkcontrollermultitouch/SdkControllerMultitouchActivity.java index 810eb80..ce4ac1d 100644 --- a/apps/SdkController/SdkControllerMultitouch/src/com/android/tools/sdkcontroller/sdkcontrollermultitouch/SdkControllerMultitouchActivity.java +++ b/apps/SdkController/SdkControllerMultitouch/src/com/android/tools/sdkcontroller/sdkcontrollermultitouch/SdkControllerMultitouchActivity.java @@ -16,39 +16,52 @@ package com.android.tools.sdkcontroller.sdkcontrollermultitouch; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + import android.app.Activity; +import android.graphics.Color; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; +import android.view.WindowManager; import com.android.tools.sdkcontroller.lib.Emulator; import com.android.tools.sdkcontroller.lib.Emulator.EmulatorConnectionType; import com.android.tools.sdkcontroller.lib.OnEmulatorListener; -import java.io.IOException; - /** * Encapsulates an application that monitors multi-touch activities on a device, * and reports them to an Android Emulator application running on the host - * machine. This application is used to provide a realistic multi-touch emulation - * in Android Emulator. + * machine. This application is used to provide a realistic multi-touch + * emulation in Android Emulator. */ public class SdkControllerMultitouchActivity extends Activity implements OnEmulatorListener { /** Tag for logging messages. */ private static final String TAG = "SdkControllerMultitouch"; + /** Received frame is JPEG image. */ + private static final int FRAME_JPEG = 1; + /** Received frame is RGB565 bitmap. */ + private static final int FRAME_RGB565 = 2; + /** Received frame is RGB888 bitmap. */ + private static final int FRAME_RGB888 = 3; /** TCP over USB connection to the emulator. */ private Emulator mEmulator; /** View for this application. */ - private View mView; + private MultiTouchView mView; /** Listener to touch events. */ private TouchListener mTouchListener; - /** Multiplier for an X coordinate of a pointer. */ - private float mDx = 1; - /** Multiplier for a Y coordinate of a pointer. */ - private float mDy = 1; + /** Width of the emulator's display. */ + private int mEmulatorWidth = 0; + /** Height of the emulator's display. */ + private int mEmulatorHeight = 0; + /** Bitmap storage. */ + private int[] mColors; /** * Implements OnTouchListener interface that receives touch screen events, @@ -56,7 +69,7 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula */ class TouchListener implements OnTouchListener { /** - * Touchscreen event handler. + * Touch screen event handler. */ @Override public boolean onTouch(View v, MotionEvent event) { @@ -73,19 +86,19 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula case MotionEvent.ACTION_MOVE: sb.append("action=move"); for (int n = 0; n < event.getPointerCount(); n++) { - constructEventMessage(sb, event, n); + mView.constructEventMessage(sb, event, n); } break; case MotionEvent.ACTION_DOWN: sb.append("action=down"); - constructEventMessage(sb, event, action_pid_index); + mView.constructEventMessage(sb, event, action_pid_index); break; case MotionEvent.ACTION_UP: sb.append("action=up pid=").append(event.getPointerId(action_pid_index)); break; case MotionEvent.ACTION_POINTER_DOWN: sb.append("action=pdown"); - constructEventMessage(sb, event, action_pid_index); + mView.constructEventMessage(sb, event, action_pid_index); break; case MotionEvent.ACTION_POINTER_UP: sb.append("action=pup pid=").append(event.getPointerId(action_pid_index)); @@ -99,21 +112,6 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula mEmulator.sendNotification(sb.toString() + '\0'); return true; } - - /** - * Constructs touch event message to be send to emulator. - *<p/> - * @param sb String builder where to construct the message. - * @param event Event for which to construct the message. - * @param ptr_index Index of the motion pointer for which to construct - * the message. - */ - private void constructEventMessage(StringBuilder sb, MotionEvent event, int ptr_index) { - sb.append(" pid=").append(event.getPointerId(ptr_index)); - sb.append(" x=").append((int) (mDx * event.getX(ptr_index))); - sb.append(" y=").append((int) (mDy * event.getY(ptr_index))); - sb.append(" pressure=").append((int) event.getPressure(ptr_index)); - } } // TouchListener /** Called when the activity is first created. */ @@ -121,6 +119,8 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); + mView = (MultiTouchView) findViewById(R.id.imageView); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // Instantiate emulator connector. try { @@ -132,10 +132,39 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula } // Create listener for touch events. - mView = findViewById(R.id.imageView); mTouchListener = new TouchListener(); } + /** + * Updates application's screen accordingly to the emulator screen. + * + * @param e_width Width of the emulator screen. + * @param e_height Height of the emulator screen. + */ + private void updateDisplay(int e_width, int e_height) { + if (e_width != mEmulatorWidth || e_height != mEmulatorHeight) { + mEmulatorWidth = e_width; + mEmulatorHeight = e_height; + + boolean rotateDisplay = false; + int w = mView.getWidth(); + int h = mView.getHeight(); + if (w > h != e_width > e_height) { + rotateDisplay = true; + int tmp = w; + w = h; + h = tmp; + } + + float dx = (float) w / (float) e_width; + float dy = (float) h / (float) e_height; + mView.setDxDy(dx, dy, rotateDisplay); + Logv("Dispay updated: " + e_width + " x " + e_height + + " -> " + w + " x " + h + " ratio: " + + dx + " x " + dy); + } + } + /*************************************************************************** * OnEmulatorListener implementation **************************************************************************/ @@ -147,6 +176,7 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula */ @Override public void onEmulatorConnected() { + Logv("Emulator is connected"); } /** @@ -154,6 +184,7 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula */ @Override public void onEmulatorDisconnected() { + Logv("Emulator is disconnected."); // Stop listening on events, and let it cool for a sec... onStopEvents(); try { @@ -166,7 +197,7 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula mEmulator = new Emulator(Emulator.MULTITOUCH_PORT, EmulatorConnectionType.SYNC_CONNECTION, this); } catch (IOException e) { - Loge("Exception while creating server socket: " + e.getMessage()); + Loge("Exception while recreating server socket: " + e.getMessage()); finish(); } } @@ -174,11 +205,11 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula /** * Called when a query is received from the emulator. NOTE: This method is * called from the I/O loop. - *<p/> + * * @param query Name of the query received from the emulator. The allowed - * queries are: - * - 'start' - Starts delivering touch screen events to the emulator. - * - 'stop' - Stops delivering touch screen events to the emulator. + * queries are: - 'start' - Starts delivering touch screen events + * to the emulator. - 'stop' - Stops delivering touch screen + * events to the emulator. * @param param Query parameters. * @return Zero-terminated reply string. String must be formatted as such: * "ok|ko[:reply data]" @@ -195,13 +226,105 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula } } + /** + * Called when a BLOB query is received from the emulator. + * <p/> + * This query is used to deliver framebuffer updates in the emulator. The + * blob contains an update header, followed by the bitmap containing updated + * rectangle. The header is defined as MTFrameHeader structure in + * external/qemu/android/multitouch-port.h + * <p/> + * NOTE: This method is called from the I/O loop, so all communication with + * the emulator will be "on hold" until this method returns. + * + * @param array contains BLOB data for the query. + * @return Empty string: this query doesn't require any response. + */ + @Override + public String onEmulatorBlobQuery(byte[] array) { + final ByteBuffer bb = ByteBuffer.wrap(array); + bb.order(ByteOrder.LITTLE_ENDIAN); + + // Read frame header. + final int header_size = bb.getInt(); + final int disp_width = bb.getInt(); + final int disp_height = bb.getInt(); + final int x = bb.getInt(); + final int y = bb.getInt(); + final int w = bb.getInt(); + final int h = bb.getInt(); + final int bpl = bb.getInt(); + final int bpp = bb.getInt(); + final int format = bb.getInt(); + + // Update application display. + updateDisplay(disp_width, disp_height); + + mView.post(new Runnable() { + @Override + public void run() { + if (format == FRAME_JPEG) { + /* + * Framebuffer is in JPEG format. + */ + + final ByteArrayInputStream jpg = new ByteArrayInputStream(bb.array()); + // Advance input stream to JPEG image. + jpg.skip(header_size); + // Draw the image. + mView.drawJpeg(x, y, w, h, jpg); + } else { + /* + * Framebuffer is in a raw RGB format. + */ + + final int pixel_num = h * w; + // Advance stream to the beginning of framebuffer data. + bb.position(header_size); + + // Make sure that mColors is large enough to contain the + // update bitmap. + if (mColors == null || mColors.length < pixel_num) { + mColors = new int[pixel_num]; + } + + // Convert the blob bitmap into bitmap that we will display. + if (format == FRAME_RGB565) { + for (int n = 0; n < pixel_num; n++) { + // Blob bitmap is in RGB565 format. + final int color = bb.getShort(); + final int r = ((color & 0xf800) >> 8) | ((color & 0xf800) >> 14); + final int g = ((color & 0x7e0) >> 3) | ((color & 0x7e0) >> 9); + final int b = ((color & 0x1f) << 3) | ((color & 0x1f) >> 2); + mColors[n] = Color.rgb(r, g, b); + } + } else if (format == FRAME_RGB888) { + for (int n = 0; n < pixel_num; n++) { + // Blob bitmap is in RGB565 format. + final int r = bb.getChar(); + final int g = bb.getChar(); + final int b = bb.getChar(); + mColors[n] = Color.rgb(r, g, b); + } + } else { + Logw("Invalid framebuffer format: " + format); + return; + } + mView.drawBitmap(x, y, w, h, mColors); + } + } + }); + + return ""; + } + /*************************************************************************** * Emulator query handlers **************************************************************************/ /** * Handles 'start' query. - *<p/> + * * @return 'ok:<WidthxHeight> on success, or 'ko:<reason>' on failure. Width * and height returned on success represent width and height of the * application view. @@ -210,15 +333,12 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula // Lets see if query has parameters. int sep = param.indexOf('x'); if (sep != -1) { - String dx = param.substring(0, sep); - String dy = param.substring(sep + 1); - int x = Integer.parseInt(dx); - int y = Integer.parseInt(dy); - mDy = (float) y / (float) mView.getHeight(); - mDx = (float) x / (float) mView.getWidth(); - Logv("Emulator: " + x + "x" + y + - " to screen: " + mView.getWidth() + "x" + mView.getHeight() + " ratio: " + - mDx + "x" + mDy); + final String dx = param.substring(0, sep); + final String dy = param.substring(sep + 1); + final int x = Integer.parseInt(dx); + final int y = Integer.parseInt(dy); + + updateDisplay(x, y); } onStartEvents(); return "ok:" + mView.getWidth() + "x" + mView.getHeight() + "\0"; @@ -226,7 +346,7 @@ public class SdkControllerMultitouchActivity extends Activity implements OnEmula /** * Handles 'stop' query. - *<p/> + * * @return 'ok'. */ private String onQueryStop() { |