• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
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
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,
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.
15  */
16 
17 package com.android.development;
18 
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.ViewConfiguration;
28 import android.view.WindowManager;
29 import android.view.VelocityTracker;
30 import android.view.View;
31 
32 import java.util.ArrayList;
33 
34 /**
35  * Demonstrates wrapping a layout in a ScrollView.
36  *
37  */
38 public class PointerLocation extends Activity {
39     @Override
onCreate(Bundle icicle)40     protected void onCreate(Bundle icicle) {
41         super.onCreate(icicle);
42         setContentView(new MyView(this));
43 
44         // Make the screen full bright for this activity.
45         WindowManager.LayoutParams lp = getWindow().getAttributes();
46         lp.screenBrightness = 1.0f;
47         getWindow().setAttributes(lp);
48     }
49 
50     public static class PointerState {
51         private final ArrayList<Float> mXs = new ArrayList<Float>();
52         private final ArrayList<Float> mYs = new ArrayList<Float>();
53         private boolean mCurDown;
54         private int mCurX;
55         private int mCurY;
56         private float mCurPressure;
57         private float mCurSize;
58         private int mCurWidth;
59         private VelocityTracker mVelocity;
60     }
61 
62     public class MyView extends View {
63         private final ViewConfiguration mVC;
64         private final Paint mTextPaint;
65         private final Paint mTextBackgroundPaint;
66         private final Paint mTextLevelPaint;
67         private final Paint mPaint;
68         private final Paint mTargetPaint;
69         private final Paint mPathPaint;
70         private final FontMetricsInt mTextMetrics = new FontMetricsInt();
71         private int mHeaderBottom;
72         private boolean mCurDown;
73         private int mCurNumPointers;
74         private int mMaxNumPointers;
75         private final ArrayList<PointerState> mPointers
76                  = new ArrayList<PointerState>();
77 
MyView(Context c)78         public MyView(Context c) {
79             super(c);
80             mVC = ViewConfiguration.get(c);
81             mTextPaint = new Paint();
82             mTextPaint.setAntiAlias(true);
83             mTextPaint.setTextSize(10
84                     * getResources().getDisplayMetrics().density);
85             mTextPaint.setARGB(255, 0, 0, 0);
86             mTextBackgroundPaint = new Paint();
87             mTextBackgroundPaint.setAntiAlias(false);
88             mTextBackgroundPaint.setARGB(128, 255, 255, 255);
89             mTextLevelPaint = new Paint();
90             mTextLevelPaint.setAntiAlias(false);
91             mTextLevelPaint.setARGB(192, 255, 0, 0);
92             mPaint = new Paint();
93             mPaint.setAntiAlias(true);
94             mPaint.setARGB(255, 255, 255, 255);
95             mPaint.setStyle(Paint.Style.STROKE);
96             mPaint.setStrokeWidth(2);
97             mTargetPaint = new Paint();
98             mTargetPaint.setAntiAlias(false);
99             mTargetPaint.setARGB(255, 0, 0, 192);
100             mPathPaint = new Paint();
101             mPathPaint.setAntiAlias(false);
102             mPathPaint.setARGB(255, 0, 96, 255);
103             mPaint.setStyle(Paint.Style.STROKE);
104             mPaint.setStrokeWidth(1);
105 
106             PointerState ps = new PointerState();
107             ps.mVelocity = VelocityTracker.obtain();
108             mPointers.add(ps);
109         }
110 
111         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)112         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
113             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
114             mTextPaint.getFontMetricsInt(mTextMetrics);
115             mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2;
116             Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent
117                     + " descent=" + mTextMetrics.descent
118                     + " leading=" + mTextMetrics.leading
119                     + " top=" + mTextMetrics.top
120                     + " bottom=" + mTextMetrics.bottom);
121         }
122 
123         @Override
onDraw(Canvas canvas)124         protected void onDraw(Canvas canvas) {
125             final int w = getWidth();
126             final int itemW = w/7;
127             final int base = -mTextMetrics.ascent+1;
128             final int bottom = mHeaderBottom;
129 
130             final int NP = mPointers.size();
131 
132             if (NP > 0) {
133                 final PointerState ps = mPointers.get(0);
134                 canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint);
135                 canvas.drawText("P: " + mCurNumPointers + " / " + mMaxNumPointers,
136                         1, base, mTextPaint);
137 
138                 final int N = ps.mXs.size();
139                 if ((mCurDown && ps.mCurDown) || N == 0) {
140                     canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint);
141                     canvas.drawText("X: " + ps.mCurX, 1 + itemW, base, mTextPaint);
142                     canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint);
143                     canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base, mTextPaint);
144                 } else {
145                     float dx = ps.mXs.get(N-1) - ps.mXs.get(0);
146                     float dy = ps.mYs.get(N-1) - ps.mYs.get(0);
147                     canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom,
148                             Math.abs(dx) < mVC.getScaledTouchSlop()
149                             ? mTextBackgroundPaint : mTextLevelPaint);
150                     canvas.drawText("dX: " + String.format("%.1f", dx), 1 + itemW, base, mTextPaint);
151                     canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom,
152                             Math.abs(dy) < mVC.getScaledTouchSlop()
153                             ? mTextBackgroundPaint : mTextLevelPaint);
154                     canvas.drawText("dY: " + String.format("%.1f", dy), 1 + itemW * 2, base, mTextPaint);
155                 }
156 
157                 canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint);
158                 int velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getXVelocity() * 1000);
159                 canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, mTextPaint);
160 
161                 canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint);
162                 velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getYVelocity() * 1000);
163                 canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, mTextPaint);
164 
165                 canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint);
166                 canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCurPressure * itemW) - 1,
167                         bottom, mTextLevelPaint);
168                 canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), 1 + itemW * 5,
169                         base, mTextPaint);
170 
171                 canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint);
172                 canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) - 1,
173                         bottom, mTextLevelPaint);
174                 canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize), 1 + itemW * 6,
175                         base, mTextPaint);
176             }
177 
178             for (int p=0; p<NP; p++) {
179                 final PointerState ps = mPointers.get(p);
180 
181                 if (mCurDown && ps.mCurDown) {
182                     canvas.drawLine(0, (int)ps.mCurY, getWidth(), (int)ps.mCurY, mTargetPaint);
183                     canvas.drawLine((int)ps.mCurX, 0, (int)ps.mCurX, getHeight(), mTargetPaint);
184                     int pressureLevel = (int)(ps.mCurPressure*255);
185                     mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel);
186                     canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint);
187                     canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint);
188                 }
189             }
190 
191             for (int p=0; p<NP; p++) {
192                 final PointerState ps = mPointers.get(p);
193 
194                 final int N = ps.mXs.size();
195                 float lastX=0, lastY=0;
196                 boolean haveLast = false;
197                 boolean drawn = false;
198                 mPaint.setARGB(255, 128, 255, 255);
199                 for (int i=0; i<N; i++) {
200                     float x = ps.mXs.get(i);
201                     float y = ps.mYs.get(i);
202                     if (Float.isNaN(x)) {
203                         haveLast = false;
204                         continue;
205                     }
206                     if (haveLast) {
207                         canvas.drawLine(lastX, lastY, x, y, mPathPaint);
208                         canvas.drawPoint(lastX, lastY, mPaint);
209                         drawn = true;
210                     }
211                     lastX = x;
212                     lastY = y;
213                     haveLast = true;
214                 }
215 
216                 if (drawn) {
217                     if (ps.mVelocity != null) {
218                         mPaint.setARGB(255, 255, 64, 128);
219                         float xVel = ps.mVelocity.getXVelocity() * (1000/60);
220                         float yVel = ps.mVelocity.getYVelocity() * (1000/60);
221                         canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint);
222                     } else {
223                         canvas.drawPoint(lastX, lastY, mPaint);
224                     }
225                 }
226             }
227         }
228 
229         @Override
onTouchEvent(MotionEvent event)230         public boolean onTouchEvent(MotionEvent event) {
231             int action = event.getAction();
232 
233             //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action)
234             //        + " pointers=" + event.getPointerCount());
235 
236             int NP = mPointers.size();
237 
238             //mRect.set(0, 0, getWidth(), mHeaderBottom+1);
239             //invalidate(mRect);
240             //if (mCurDown) {
241             //    mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
242             //            mCurX+mCurWidth+3, mCurY+mCurWidth+3);
243             //} else {
244             //    mRect.setEmpty();
245             //}
246             if (action == MotionEvent.ACTION_DOWN) {
247                 for (int p=0; p<NP; p++) {
248                     final PointerState ps = mPointers.get(p);
249                     ps.mXs.clear();
250                     ps.mYs.clear();
251                     ps.mVelocity = VelocityTracker.obtain();
252                     ps.mCurDown = false;
253                 }
254                 mPointers.get(0).mCurDown = true;
255                 mMaxNumPointers = 0;
256                 Log.i("Pointer", "Pointer 1: DOWN");
257             }
258 
259             if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
260                 final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK)
261                         >> MotionEvent.ACTION_POINTER_ID_SHIFT;
262                 while (NP <= id) {
263                     PointerState ps = new PointerState();
264                     ps.mVelocity = VelocityTracker.obtain();
265                     mPointers.add(ps);
266                     NP++;
267                 }
268                 final PointerState ps = mPointers.get(id);
269                 ps.mVelocity = VelocityTracker.obtain();
270                 ps.mCurDown = true;
271                 Log.i("Pointer", "Pointer " + (id+1) + ": DOWN");
272             }
273 
274             final int NI = event.getPointerCount();
275 
276             mCurDown = action != MotionEvent.ACTION_UP
277                     && action != MotionEvent.ACTION_CANCEL;
278             mCurNumPointers = mCurDown ? NI : 0;
279             if (mMaxNumPointers < mCurNumPointers) {
280                 mMaxNumPointers = mCurNumPointers;
281             }
282 
283             for (int i=0; i<NI; i++) {
284                 final PointerState ps = mPointers.get(event.getPointerId(i));
285                 ps.mVelocity.addMovement(event);
286                 ps.mVelocity.computeCurrentVelocity(1);
287                 final int N = event.getHistorySize();
288                 for (int j=0; j<N; j++) {
289                     Log.i("Pointer", "Pointer " + (i+1) + ": ("
290                             + event.getHistoricalX(i, j)
291                             + ", " + event.getHistoricalY(i, j) + ")"
292                             + " Prs=" + event.getHistoricalPressure(i, j)
293                             + " Size=" + event.getHistoricalSize(i, j));
294                     ps.mXs.add(event.getHistoricalX(i, j));
295                     ps.mYs.add(event.getHistoricalY(i, j));
296                 }
297                 Log.i("Pointer", "Pointer " + (i+1) + ": ("
298                         + event.getX(i) + ", " + event.getY(i) + ")"
299                         + " Prs=" + event.getPressure(i)
300                         + " Size=" + event.getSize(i));
301                 ps.mXs.add(event.getX(i));
302                 ps.mYs.add(event.getY(i));
303                 ps.mCurX = (int)event.getX(i);
304                 ps.mCurY = (int)event.getY(i);
305                 //Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX
306                 //        + "," + ps.mCurY + ")");
307                 ps.mCurPressure = event.getPressure(i);
308                 ps.mCurSize = event.getSize(i);
309                 ps.mCurWidth = (int)(ps.mCurSize*(getWidth()/3));
310             }
311 
312             if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
313                 final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK)
314                         >> MotionEvent.ACTION_POINTER_ID_SHIFT;
315                 final PointerState ps = mPointers.get(id);
316                 ps.mXs.add(Float.NaN);
317                 ps.mYs.add(Float.NaN);
318                 ps.mCurDown = false;
319                 Log.i("Pointer", "Pointer " + (id+1) + ": UP");
320             }
321 
322             if (action == MotionEvent.ACTION_UP) {
323                 for (int i=0; i<NI; i++) {
324                     final PointerState ps = mPointers.get(event.getPointerId(i));
325                     if (ps.mCurDown) {
326                         ps.mCurDown = false;
327                         Log.i("Pointer", "Pointer " + (i+1) + ": UP");
328                     }
329                 }
330             }
331 
332             //if (mCurDown) {
333             //    mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
334             //            mCurX+mCurWidth+3, mCurY+mCurWidth+3);
335             //}
336             //invalidate(mRect);
337             invalidate();
338             return true;
339         }
340 
341     }
342 }
343