Home | History | Annotate | Download | only in views
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.tools.sdkcontroller.views;
     18 
     19 import java.io.InputStream;
     20 import java.nio.ByteBuffer;
     21 
     22 import android.content.Context;
     23 import android.graphics.Bitmap;
     24 import android.graphics.BitmapFactory;
     25 import android.graphics.Canvas;
     26 import android.graphics.Matrix;
     27 import android.graphics.Paint;
     28 import android.util.AttributeSet;
     29 import android.util.Log;
     30 import android.view.MotionEvent;
     31 import android.view.View;
     32 
     33 /**
     34  * Implements a main view for the application providing multi-touch emulation.
     35  */
     36 public class MultiTouchView extends View {
     37     /** Tag for logging messages. */
     38     private static final String TAG = MultiTouchView.class.getSimpleName();
     39     /**
     40      * Back-end bitmap. Initialized in onSizeChanged(), updated in
     41      * onTouchEvent() and drawn in onDraw().
     42      */
     43     private Bitmap mBitmap;
     44     /** Default Paint instance for drawing the bitmap. */
     45     private final Paint mPaint = new Paint();
     46     /** Canvas instance for this view. */
     47     private Canvas mCanvas;
     48     /** Emulator screen width to this view width ratio. */
     49     private float mDx = 1;
     50     /** Emulator screen height to this view height ratio. */
     51     private float mDy = 1;
     52     /**
     53      * Flags whether or not image received from the emulator should be rotated.
     54      * Rotation is required when display orientation state of the emulator and
     55      * the device doesn't match.
     56      */
     57     private boolean mRotateDisplay;
     58     /** Base matrix that keep emulator->device display scaling */
     59     private Matrix mBaseMatrix = new Matrix();
     60     /** Matrix that is used to draw emulator's screen on the device. */
     61     private Matrix mDrawMatrix = new Matrix();
     62 
     63     /**
     64      * Simple constructor to use when creating a view from code.
     65      *
     66      * @see View#View(Context)
     67      */
     68     public MultiTouchView(Context context) {
     69         this(context, null);
     70     }
     71 
     72     /**
     73      * Constructor that is called when inflating a view from XML.
     74      *
     75      * @see View#View(Context, AttributeSet)
     76      */
     77     public MultiTouchView(Context context, AttributeSet attrs) {
     78         this(context, attrs, 0);
     79     }
     80 
     81     /**
     82      * Perform inflation from XML and apply a class-specific base style.
     83      *
     84      * @see View#View(Context, AttributeSet, int)
     85      */
     86     public MultiTouchView(Context context, AttributeSet attrs, int defStyle) {
     87         super(context, attrs, defStyle);
     88 
     89         // TODO Add constructor-time code here.
     90     }
     91 
     92     @Override
     93     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     94         super.onSizeChanged(w, h, oldw, oldh);
     95 
     96         mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
     97         mCanvas = new Canvas(mBitmap);
     98     }
     99 
    100     @Override
    101     protected void onDraw(Canvas canvas) {
    102         super.onDraw(canvas);
    103         // Just draw the back-end bitmap without zooming or scaling.
    104         if (mBitmap != null) {
    105             canvas.drawBitmap(mBitmap, 0, 0, null);
    106         }
    107     }
    108 
    109     /**
    110      * Sets emulator screen width and height to this view width and height
    111      * ratio.
    112      *
    113      * @param dx Emulator screen width to this view width ratio.
    114      * @param dy Emulator screen height to this view height ratio.
    115      * @param rotateDisplay Flags whether image received from the emulator
    116      *            should be rotated when drawn on the device.
    117      */
    118     public void setDxDy(float dx, float dy, boolean rotateDisplay) {
    119         mDx = dx;
    120         mDy = dy;
    121         mRotateDisplay = rotateDisplay;
    122 
    123         mBaseMatrix.setScale(dx, dy);
    124         if (mRotateDisplay) {
    125             mBaseMatrix.postRotate(90);
    126             mBaseMatrix.postTranslate(getWidth(), 0);
    127         }
    128     }
    129 
    130     /**
    131      * Computes draw matrix for the emulator screen update.
    132      *
    133      * @param x Left screen coordinate of the bitmap on emulator screen.
    134      * @param y Top screen coordinate of the bitmap on emulator screen.
    135      */
    136     private void computeDrawMatrix(int x, int y) {
    137         mDrawMatrix.set(mBaseMatrix);
    138         if (mRotateDisplay) {
    139             mDrawMatrix.postTranslate(-y * mDy, x * mDx);
    140         } else {
    141             mDrawMatrix.postTranslate(x * mDx, y * mDy);
    142         }
    143     }
    144 
    145     /**
    146      * Draws a bitmap on the screen.
    147      *
    148      * @param x Left screen coordinate of the bitmap on emulator screen.
    149      * @param y Top screen coordinate of the bitmap on emulator screen.
    150      * @param w Width of the bitmap on the emulator screen.
    151      * @param h Height of the bitmap on the emulator screen.
    152      * @param colors Bitmap to draw.
    153      */
    154     public void drawBitmap(int x, int y, int w, int h, int[] colors) {
    155         if (mCanvas != null) {
    156             final Bitmap bmp = Bitmap.createBitmap(colors, 0, w, w, h, Bitmap.Config.ARGB_8888);
    157 
    158             computeDrawMatrix(x, y);
    159 
    160             /* Draw the bitmap and invalidate the updated region. */
    161             mCanvas.drawBitmap(bmp, mDrawMatrix, mPaint);
    162             invalidate();
    163         }
    164     }
    165 
    166     /**
    167      * Draws a JPEG bitmap on the screen.
    168      *
    169      * @param x Left screen coordinate of the bitmap on emulator screen.
    170      * @param y Top screen coordinate of the bitmap on emulator screen.
    171      * @param w Width of the bitmap on the emulator screen.
    172      * @param h Height of the bitmap on the emulator screen.
    173      * @param jpeg JPEG bitmap to draw.
    174      */
    175     public void drawJpeg(int x, int y, int w, int h, InputStream jpeg) {
    176         if (mCanvas != null) {
    177             final Bitmap bmp = BitmapFactory.decodeStream(jpeg);
    178 
    179             computeDrawMatrix(x, y);
    180 
    181             /* Draw the bitmap and invalidate the updated region. */
    182             mCanvas.drawBitmap(bmp, mDrawMatrix, mPaint);
    183             invalidate();
    184         }
    185     }
    186 
    187     /**
    188      * Constructs touch event message to be send to emulator.
    189      *
    190      * @param bb ByteBuffer where to construct the message.
    191      * @param event Event for which to construct the message.
    192      * @param ptr_index Index of the motion pointer for which to construct the
    193      *            message.
    194      */
    195     public void constructEventMessage(ByteBuffer bb, MotionEvent event, int ptr_index) {
    196         bb.putInt(event.getPointerId(ptr_index));
    197         if (mRotateDisplay == false) {
    198             bb.putInt((int) (event.getX(ptr_index) / mDx));
    199             bb.putInt((int) (event.getY(ptr_index) / mDy));
    200         } else {
    201             bb.putInt((int) (event.getY(ptr_index) / mDy));
    202             bb.putInt((int) (getWidth() - event.getX(ptr_index) / mDx));
    203         }
    204         // At the system level the input reader takes integers in the range
    205         // 0 - 100 for the pressure.
    206         int pressure = (int) (event.getPressure(ptr_index) * 100);
    207         // Make sure it doesn't exceed 100...
    208         if (pressure > 100) {
    209             pressure = 100;
    210         }
    211         bb.putInt(pressure);
    212     }
    213 
    214     /***************************************************************************
    215      * Logging wrappers
    216      **************************************************************************/
    217 
    218     @SuppressWarnings("unused")
    219     private void Loge(String log) {
    220         Log.e(TAG, log);
    221     }
    222 
    223     @SuppressWarnings("unused")
    224     private void Logw(String log) {
    225         Log.w(TAG, log);
    226     }
    227 
    228     @SuppressWarnings("unused")
    229     private void Logv(String log) {
    230         Log.v(TAG, log);
    231     }
    232 }
    233