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