| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| package com.android.tools.sdkcontroller.views; |
| |
| import java.io.InputStream; |
| import java.nio.ByteBuffer; |
| |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapFactory; |
| import android.graphics.Canvas; |
| import android.graphics.Matrix; |
| import android.graphics.Paint; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.view.MotionEvent; |
| import android.view.View; |
| |
| /** |
| * Implements a main view for the application providing multi-touch emulation. |
| */ |
| public class MultiTouchView extends View { |
| /** Tag for logging messages. */ |
| private static final String TAG = MultiTouchView.class.getSimpleName(); |
| /** |
| * Back-end bitmap. Initialized in onSizeChanged(), updated in |
| * onTouchEvent() and drawn in onDraw(). |
| */ |
| private Bitmap mBitmap; |
| /** Default Paint instance for drawing the bitmap. */ |
| private final Paint mPaint = new Paint(); |
| /** Canvas instance for this view. */ |
| private Canvas mCanvas; |
| /** Emulator screen width to this view width ratio. */ |
| private float mDx = 1; |
| /** Emulator screen height to this view height ratio. */ |
| private float mDy = 1; |
| /** |
| * Flags whether or not image received from the emulator should be rotated. |
| * Rotation is required when display orientation state of the emulator and |
| * the device doesn't match. |
| */ |
| private boolean mRotateDisplay; |
| /** Base matrix that keep emulator->device display scaling */ |
| private Matrix mBaseMatrix = new Matrix(); |
| /** Matrix that is used to draw emulator's screen on the device. */ |
| private Matrix mDrawMatrix = new Matrix(); |
| |
| /** |
| * Simple constructor to use when creating a view from code. |
| * |
| * @see View#View(Context) |
| */ |
| public MultiTouchView(Context context) { |
| this(context, null); |
| } |
| |
| /** |
| * Constructor that is called when inflating a view from XML. |
| * |
| * @see View#View(Context, AttributeSet) |
| */ |
| public MultiTouchView(Context context, AttributeSet attrs) { |
| this(context, attrs, 0); |
| } |
| |
| /** |
| * Perform inflation from XML and apply a class-specific base style. |
| * |
| * @see View#View(Context, AttributeSet, int) |
| */ |
| public MultiTouchView(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| |
| // TODO Add constructor-time code here. |
| } |
| |
| @Override |
| protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
| super.onSizeChanged(w, h, oldw, oldh); |
| |
| mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); |
| mCanvas = new Canvas(mBitmap); |
| } |
| |
| @Override |
| protected void onDraw(Canvas canvas) { |
| super.onDraw(canvas); |
| // Just draw the back-end bitmap without zooming or scaling. |
| if (mBitmap != null) { |
| canvas.drawBitmap(mBitmap, 0, 0, null); |
| } |
| } |
| |
| /** |
| * Sets emulator screen width and height to this view width and height |
| * ratio. |
| * |
| * @param dx Emulator screen width to this view width ratio. |
| * @param dy Emulator screen height to this view height ratio. |
| * @param rotateDisplay Flags whether image received from the emulator |
| * should be rotated when drawn on the device. |
| */ |
| public void setDxDy(float dx, float dy, boolean rotateDisplay) { |
| mDx = dx; |
| mDy = dy; |
| mRotateDisplay = rotateDisplay; |
| |
| mBaseMatrix.setScale(dx, dy); |
| if (mRotateDisplay) { |
| mBaseMatrix.postRotate(90); |
| mBaseMatrix.postTranslate(getWidth(), 0); |
| } |
| } |
| |
| /** |
| * Computes draw matrix for the emulator screen update. |
| * |
| * @param x Left screen coordinate of the bitmap on emulator screen. |
| * @param y Top screen coordinate of the bitmap on emulator screen. |
| */ |
| private void computeDrawMatrix(int x, int y) { |
| mDrawMatrix.set(mBaseMatrix); |
| if (mRotateDisplay) { |
| mDrawMatrix.postTranslate(-y * mDy, x * mDx); |
| } else { |
| mDrawMatrix.postTranslate(x * mDx, y * mDy); |
| } |
| } |
| |
| /** |
| * Draws a bitmap on the screen. |
| * |
| * @param x Left screen coordinate of the bitmap on emulator screen. |
| * @param y Top screen coordinate of the bitmap on emulator screen. |
| * @param w Width of the bitmap on the emulator screen. |
| * @param h Height of the bitmap on the emulator screen. |
| * @param colors Bitmap to draw. |
| */ |
| public void drawBitmap(int x, int y, int w, int h, int[] colors) { |
| if (mCanvas != null) { |
| final Bitmap bmp = Bitmap.createBitmap(colors, 0, w, w, h, Bitmap.Config.ARGB_8888); |
| |
| computeDrawMatrix(x, y); |
| |
| /* Draw the bitmap and invalidate the updated region. */ |
| mCanvas.drawBitmap(bmp, mDrawMatrix, mPaint); |
| invalidate(); |
| } |
| } |
| |
| /** |
| * Draws a JPEG bitmap on the screen. |
| * |
| * @param x Left screen coordinate of the bitmap on emulator screen. |
| * @param y Top screen coordinate of the bitmap on emulator screen. |
| * @param w Width of the bitmap on the emulator screen. |
| * @param h Height of the bitmap on the emulator screen. |
| * @param jpeg JPEG bitmap to draw. |
| */ |
| public void drawJpeg(int x, int y, int w, int h, InputStream jpeg) { |
| if (mCanvas != null) { |
| final Bitmap bmp = BitmapFactory.decodeStream(jpeg); |
| |
| computeDrawMatrix(x, y); |
| |
| /* Draw the bitmap and invalidate the updated region. */ |
| mCanvas.drawBitmap(bmp, mDrawMatrix, mPaint); |
| invalidate(); |
| } |
| } |
| |
| /** |
| * Constructs touch event message to be send to emulator. |
| * |
| * @param bb ByteBuffer 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. |
| */ |
| public void constructEventMessage(ByteBuffer bb, MotionEvent event, int ptr_index) { |
| bb.putInt(event.getPointerId(ptr_index)); |
| if (mRotateDisplay == false) { |
| bb.putInt((int) (event.getX(ptr_index) / mDx)); |
| bb.putInt((int) (event.getY(ptr_index) / mDy)); |
| } else { |
| bb.putInt((int) (event.getY(ptr_index) / mDy)); |
| bb.putInt((int) (getWidth() - event.getX(ptr_index) / mDx)); |
| } |
| // At the system level the input reader takes integers in the range |
| // 0 - 100 for the pressure. |
| int pressure = (int) (event.getPressure(ptr_index) * 100); |
| // Make sure it doesn't exceed 100... |
| if (pressure > 100) { |
| pressure = 100; |
| } |
| bb.putInt(pressure); |
| } |
| |
| /*************************************************************************** |
| * Logging wrappers |
| **************************************************************************/ |
| |
| @SuppressWarnings("unused") |
| private void Loge(String log) { |
| Log.e(TAG, log); |
| } |
| |
| @SuppressWarnings("unused") |
| private void Logw(String log) { |
| Log.w(TAG, log); |
| } |
| |
| @SuppressWarnings("unused") |
| private void Logv(String log) { |
| Log.v(TAG, log); |
| } |
| } |