2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.development;
19 import android.app.Activity;
20 import android.content.Context;
21 import android.graphics.Canvas;
22 import android.graphics.Paint;
23 import android.graphics.Paint.FontMetricsInt;
24 import android.os.Bundle;
25 import android.util.Log;
26 import android.view.MotionEvent;
27 import android.view.WindowManager;
28 import android.view.VelocityTracker;
29 import android.view.View;
31 import java.util.ArrayList;
34 * Demonstrates wrapping a layout in a ScrollView.
37 public class PointerLocation extends Activity {
39 protected void onCreate(Bundle icicle) {
40 super.onCreate(icicle);
41 setContentView(new MyView(this));
43 // Make the screen full bright for this activity.
44 WindowManager.LayoutParams lp = getWindow().getAttributes();
45 lp.screenBrightness = 1.0f;
46 getWindow().setAttributes(lp);
49 public static class PointerState {
50 private final ArrayList<Float> mXs = new ArrayList<Float>();
51 private final ArrayList<Float> mYs = new ArrayList<Float>();
52 private boolean mCurDown;
55 private float mCurPressure;
56 private float mCurSize;
57 private int mCurWidth;
58 private VelocityTracker mVelocity;
61 public class MyView extends View {
62 private final Paint mTextPaint;
63 private final Paint mTextBackgroundPaint;
64 private final Paint mTextLevelPaint;
65 private final Paint mPaint;
66 private final Paint mTargetPaint;
67 private final Paint mPathPaint;
68 private final FontMetricsInt mTextMetrics = new FontMetricsInt();
69 private int mHeaderBottom;
70 private boolean mCurDown;
71 private int mCurNumPointers;
72 private int mMaxNumPointers;
73 private final ArrayList<PointerState> mPointers
74 = new ArrayList<PointerState>();
76 public MyView(Context c) {
78 mTextPaint = new Paint();
79 mTextPaint.setAntiAlias(true);
80 mTextPaint.setTextSize(10
81 * getResources().getDisplayMetrics().density);
82 mTextPaint.setARGB(255, 0, 0, 0);
83 mTextBackgroundPaint = new Paint();
84 mTextBackgroundPaint.setAntiAlias(false);
85 mTextBackgroundPaint.setARGB(128, 255, 255, 255);
86 mTextLevelPaint = new Paint();
87 mTextLevelPaint.setAntiAlias(false);
88 mTextLevelPaint.setARGB(192, 255, 0, 0);
90 mPaint.setAntiAlias(true);
91 mPaint.setARGB(255, 255, 255, 255);
92 mPaint.setStyle(Paint.Style.STROKE);
93 mPaint.setStrokeWidth(2);
94 mTargetPaint = new Paint();
95 mTargetPaint.setAntiAlias(false);
96 mTargetPaint.setARGB(255, 0, 0, 192);
97 mPathPaint = new Paint();
98 mPathPaint.setAntiAlias(false);
99 mPathPaint.setARGB(255, 0, 96, 255);
100 mPaint.setStyle(Paint.Style.STROKE);
101 mPaint.setStrokeWidth(1);
103 PointerState ps = new PointerState();
104 ps.mVelocity = VelocityTracker.obtain();
109 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
110 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
111 mTextPaint.getFontMetricsInt(mTextMetrics);
112 mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2;
113 Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent
114 + " descent=" + mTextMetrics.descent
115 + " leading=" + mTextMetrics.leading
116 + " top=" + mTextMetrics.top
117 + " bottom=" + mTextMetrics.bottom);
121 protected void onDraw(Canvas canvas) {
122 final int w = getWidth();
123 final int itemW = w/7;
124 final int base = -mTextMetrics.ascent+1;
125 final int bottom = mHeaderBottom;
127 final int NP = mPointers.size();
130 final PointerState ps = mPointers.get(0);
131 canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint);
132 canvas.drawText("P: " + mCurNumPointers + " / " + mMaxNumPointers,
133 1, base, mTextPaint);
135 canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint);
136 canvas.drawText("X: " + ps.mCurX, 1 + itemW, base, mTextPaint);
138 canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint);
139 canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base, mTextPaint);
141 canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint);
142 int velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getXVelocity() * 1000);
143 canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, mTextPaint);
145 canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint);
146 velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getYVelocity() * 1000);
147 canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, mTextPaint);
149 canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint);
150 canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCurPressure * itemW) - 1,
151 bottom, mTextLevelPaint);
152 canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), 1 + itemW * 5,
155 canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint);
156 canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) - 1,
157 bottom, mTextLevelPaint);
158 canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize), 1 + itemW * 6,
162 for (int p=0; p<NP; p++) {
163 final PointerState ps = mPointers.get(p);
165 if (mCurDown && ps.mCurDown) {
166 canvas.drawLine(0, (int)ps.mCurY, getWidth(), (int)ps.mCurY, mTargetPaint);
167 canvas.drawLine((int)ps.mCurX, 0, (int)ps.mCurX, getHeight(), mTargetPaint);
168 int pressureLevel = (int)(ps.mCurPressure*255);
169 mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel);
170 canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint);
171 canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint);
175 for (int p=0; p<NP; p++) {
176 final PointerState ps = mPointers.get(p);
178 final int N = ps.mXs.size();
179 float lastX=0, lastY=0;
180 boolean haveLast = false;
181 boolean drawn = false;
182 mPaint.setARGB(255, 128, 255, 255);
183 for (int i=0; i<N; i++) {
184 float x = ps.mXs.get(i);
185 float y = ps.mYs.get(i);
186 if (Float.isNaN(x)) {
191 canvas.drawLine(lastX, lastY, x, y, mPathPaint);
192 canvas.drawPoint(lastX, lastY, mPaint);
201 if (ps.mVelocity != null) {
202 mPaint.setARGB(255, 255, 64, 128);
203 float xVel = ps.mVelocity.getXVelocity() * (1000/60);
204 float yVel = ps.mVelocity.getYVelocity() * (1000/60);
205 canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint);
207 canvas.drawPoint(lastX, lastY, mPaint);
214 public boolean onTouchEvent(MotionEvent event) {
215 int action = event.getAction();
217 //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action)
218 // + " pointers=" + event.getPointerCount());
220 int NP = mPointers.size();
222 //mRect.set(0, 0, getWidth(), mHeaderBottom+1);
225 // mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
226 // mCurX+mCurWidth+3, mCurY+mCurWidth+3);
230 if (action == MotionEvent.ACTION_DOWN) {
231 for (int p=0; p<NP; p++) {
232 final PointerState ps = mPointers.get(p);
235 ps.mVelocity = VelocityTracker.obtain();
238 mPointers.get(0).mCurDown = true;
242 if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
243 final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK)
244 >> MotionEvent.ACTION_POINTER_ID_SHIFT;
246 PointerState ps = new PointerState();
247 ps.mVelocity = VelocityTracker.obtain();
251 final PointerState ps = mPointers.get(id);
252 ps.mVelocity = VelocityTracker.obtain();
256 final int NI = event.getPointerCount();
258 mCurDown = action != MotionEvent.ACTION_UP
259 && action != MotionEvent.ACTION_CANCEL;
260 mCurNumPointers = mCurDown ? NI : 0;
261 if (mMaxNumPointers < mCurNumPointers) {
262 mMaxNumPointers = mCurNumPointers;
265 for (int i=0; i<NI; i++) {
266 final PointerState ps = mPointers.get(event.getPointerId(i));
267 ps.mVelocity.addMovement(event);
268 ps.mVelocity.computeCurrentVelocity(1);
269 final int N = event.getHistorySize();
270 for (int j=0; j<N; j++) {
271 ps.mXs.add(event.getHistoricalX(i, j));
272 ps.mYs.add(event.getHistoricalY(i, j));
274 ps.mXs.add(event.getX(i));
275 ps.mYs.add(event.getY(i));
276 ps.mCurX = (int)event.getX(i);
277 ps.mCurY = (int)event.getY(i);
278 //Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX
279 // + "," + ps.mCurY + ")");
280 ps.mCurPressure = event.getPressure(i);
281 ps.mCurSize = event.getSize(i);
282 ps.mCurWidth = (int)(ps.mCurSize*(getWidth()/3));
285 if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
286 final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK)
287 >> MotionEvent.ACTION_POINTER_ID_SHIFT;
288 final PointerState ps = mPointers.get(id);
289 ps.mXs.add(Float.NaN);
290 ps.mYs.add(Float.NaN);
295 // mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
296 // mCurX+mCurWidth+3, mCurY+mCurWidth+3);