/* * Copyright (C) 2010 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.DeviceTest.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.FontMetricsInt; import android.util.AttributeSet; import android.util.Log; import android.view.*; import android.view.View.OnTouchListener; import android.widget.RelativeLayout; import java.util.ArrayList; public class PointerLocationView extends View implements OnTouchListener { public static class PointerState { private final ArrayList mXs = new ArrayList(); private final ArrayList mYs = new ArrayList(); private boolean mCurDown; private int mCurX; private int mCurY; private float mCurPressure; private float mCurSize; private int mCurWidth; private VelocityTracker mVelocity; } // private final ViewConfiguration mVC; private int NP = 0; private final Paint mTextPaint; // private final Paint mTextBackgroundPaint; // private final Paint mTextLevelPaint; private final Paint mPaint; private final Paint mTargetPaint; private final Paint mPathPaint; // private final FontMetricsInt mTextMetrics = new FontMetricsInt(); // private int mHeaderBottom; private boolean mCurDown; private int mCurNumPointers; private int mMaxNumPointers; private final ArrayList mPointers = new ArrayList(); private boolean mPrintCoords = true; public PointerLocationView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PointerLocationView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setFocusable(true); // mVC = ViewConfiguration.get(context); mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setTextSize(50 * getResources().getDisplayMetrics().density); mTextPaint.setARGB(255, 255, 0, 0); mTextPaint.setTextAlign(Align.RIGHT); /* * mTextBackgroundPaint = new Paint(); * mTextBackgroundPaint.setAntiAlias(false); * mTextBackgroundPaint.setARGB(128, 255, 255, 255); mTextLevelPaint = * new Paint(); mTextLevelPaint.setAntiAlias(false); * mTextLevelPaint.setARGB(192, 255, 0, 0); */ mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setARGB(255, 255, 255, 255); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(2); mTargetPaint = new Paint(); mTargetPaint.setAntiAlias(false); mTargetPaint.setARGB(255, 0, 0, 192); mPathPaint = new Paint(); mPathPaint.setAntiAlias(false); mPathPaint.setARGB(255, 0, 96, 255); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(1); PointerState ps = new PointerState(); ps.mVelocity = VelocityTracker.obtain(); mPointers.add(ps); } public void setPrintCoords(boolean state) { mPrintCoords = state; } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /* * mTextPaint.getFontMetricsInt(mTextMetrics); mHeaderBottom = * -mTextMetrics.ascent+mTextMetrics.descent+2; */ ((ViewGroup)getParent()).setOnTouchListener(this); } protected void onDraw(Canvas canvas) { synchronized (mPointers) { NP = mPointers.size(); /* * final int w = getWidth(); final int itemW = w/7; final int base = * -mTextMetrics.ascent+1; final int bottom = mHeaderBottom; * * * if (NP > 0) { final PointerState ps = mPointers.get(0); * canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); * canvas.drawText("P: " + mCurNumPointers + " / " + * mMaxNumPointers, 1, base, mTextPaint); * * final int N = ps.mXs.size(); if ((mCurDown && ps.mCurDown) || N * == 0) { canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, * mTextBackgroundPaint); canvas.drawText("X: " + ps.mCurX, 1 + * itemW, base, mTextPaint); canvas.drawRect(itemW * 2, 0, (itemW * * 3) - 1, bottom, mTextBackgroundPaint); canvas.drawText("Y: " + * ps.mCurY, 1 + itemW * 2, base, mTextPaint); } else { float dx = * ps.mXs.get(N-1) - ps.mXs.get(0); float dy = ps.mYs.get(N-1) - * ps.mYs.get(0); canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, * Math.abs(dx) < mVC.getScaledTouchSlop() ? mTextBackgroundPaint : * mTextLevelPaint); canvas.drawText("dX: " + String.format("%.1f", * dx), 1 + itemW, base, mTextPaint); canvas.drawRect(itemW * 2, 0, * (itemW * 3) - 1, bottom, Math.abs(dy) < mVC.getScaledTouchSlop() * ? mTextBackgroundPaint : mTextLevelPaint); canvas.drawText("dY: " * + String.format("%.1f", dy), 1 + itemW * 2, base, mTextPaint); } * * canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, * mTextBackgroundPaint); int velocity = ps.mVelocity == null ? 0 : * (int) (ps.mVelocity.getXVelocity() * 1000); * canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, * mTextPaint); * * canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, * mTextBackgroundPaint); velocity = ps.mVelocity == null ? 0 : * (int) (ps.mVelocity.getYVelocity() * 1000); * canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, * mTextPaint); * * canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, * mTextBackgroundPaint); canvas.drawRect(itemW * 5, 0, (itemW * 5) * + (ps.mCurPressure * itemW) - 1, bottom, mTextLevelPaint); * canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), * 1 + itemW * 5, base, mTextPaint); * * canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); * canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) * - 1, bottom, mTextLevelPaint); canvas.drawText("Size: " + * String.format("%.2f", ps.mCurSize), 1 + itemW * 6, base, * mTextPaint); } */ if (onPointCountChangeListener != null) { onPointCountChangeListener.onPointCountChange(mPointers.size()); } canvas.drawText("Current Point:" + mCurNumPointers, getWidth() / 2, getHeight() / 2, mTextPaint); for (int p = 0; p < NP; p++) { final PointerState ps = mPointers.get(p); if (mCurDown && ps.mCurDown) { canvas.drawLine(0, (int) ps.mCurY, getWidth(), (int) ps.mCurY, mTargetPaint); canvas.drawLine((int) ps.mCurX, 0, (int) ps.mCurX, getHeight(), mTargetPaint); int pressureLevel = (int) (ps.mCurPressure * 255); mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel); canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint); canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint); } } for (int p = 0; p < NP; p++) { final PointerState ps = mPointers.get(p); final int N = ps.mXs.size(); float lastX = 0, lastY = 0; boolean haveLast = false; boolean drawn = false; mPaint.setARGB(255, 128, 255, 255); for (int i = 0; i < N; i++) { float x = ps.mXs.get(i); float y = ps.mYs.get(i); if (Float.isNaN(x)) { haveLast = false; continue; } if (haveLast) { canvas.drawLine(lastX, lastY, x, y, mPathPaint); canvas.drawPoint(lastX, lastY, mPaint); drawn = true; } lastX = x; lastY = y; haveLast = true; } if (drawn) { if (ps.mVelocity != null) { mPaint.setARGB(255, 255, 64, 128); float xVel = ps.mVelocity.getXVelocity() * (1000 / 60); float yVel = ps.mVelocity.getYVelocity() * (1000 / 60); canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); } else { canvas.drawPoint(lastX, lastY, mPaint); } } } } } public void addTouchEvent(MotionEvent event) { synchronized (mPointers) { int action = event.getAction(); NP = mPointers.size(); if (action == MotionEvent.ACTION_DOWN) { for (int p = 0; p < NP; p++) { final PointerState ps = mPointers.get(p); ps.mXs.clear(); ps.mYs.clear(); ps.mVelocity = VelocityTracker.obtain(); ps.mCurDown = false; } mPointers.get(0).mCurDown = true; mMaxNumPointers = 0; if (mPrintCoords) { Log.i("Pointer", "Pointer 1: DOWN"); } } if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { Log.i("Pointer", "action down"); final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int id = event.getPointerId(index); while (NP <= id) { PointerState ps = new PointerState(); ps.mVelocity = VelocityTracker.obtain(); mPointers.add(ps); NP++; } final PointerState ps = mPointers.get(id); ps.mVelocity = VelocityTracker.obtain(); ps.mCurDown = true; if (mPrintCoords) { Log.i("Pointer", "Pointer " + (id + 1) + ": DOWN"); } } final int NI = event.getPointerCount(); mCurDown = action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL; mCurNumPointers = mCurDown ? NI : 0; if (mMaxNumPointers < mCurNumPointers) { mMaxNumPointers = mCurNumPointers; } for (int i = 0; i < NI; i++) { final int id = event.getPointerId(i); final PointerState ps = mPointers.get(id); ps.mVelocity.addMovement(event); ps.mVelocity.computeCurrentVelocity(1); final int N = event.getHistorySize(); for (int j = 0; j < N; j++) { if (mPrintCoords) { Log.i("Pointer", "Pointer " + (id + 1) + ": (" + event.getHistoricalX(i, j) + ", " + event.getHistoricalY(i, j) + ")" + " Prs=" + event.getHistoricalPressure(i, j) + " Size=" + event.getHistoricalSize(i, j)); } ps.mXs.add(event.getHistoricalX(i, j)); ps.mYs.add(event.getHistoricalY(i, j)); } if (mPrintCoords) { Log.i("Pointer", "Pointer " + (id + 1) + ": (" + event.getX(i) + ", " + event.getY(i) + ")" + " Prs=" + event.getPressure(i) + " Size=" + event.getSize(i)); } ps.mXs.add(event.getX(i)); ps.mYs.add(event.getY(i)); ps.mCurX = (int) event.getX(i); ps.mCurY = (int) event.getY(i); // Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX // + "," + ps.mCurY + ")"); ps.mCurPressure = event.getPressure(i); ps.mCurSize = event.getSize(i); ps.mCurWidth = (int) (ps.mCurSize * (getWidth() / 3)); } if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { Log.i("Pointer", "action up"); final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int id = event.getPointerId(index); final PointerState ps = mPointers.get(id); ps.mXs.add(Float.NaN); ps.mYs.add(Float.NaN); ps.mCurDown = false; if (mPrintCoords) { Log.i("Pointer", "Pointer " + (id + 1) + ": UP"); } } if (action == MotionEvent.ACTION_UP) { for (int i = 0; i < NI; i++) { final int id = event.getPointerId(i); final PointerState ps = mPointers.get(id); if (ps.mCurDown) { ps.mCurDown = false; if (mPrintCoords) { Log.i("Pointer", "Pointer " + (id + 1) + ": UP"); } } } } postInvalidate(); } } public interface OnPointCountChangeListener { public void onPointCountChange(int newPointCount); } private OnPointCountChangeListener onPointCountChangeListener; public void setOnPointCountChangeListener( OnPointCountChangeListener onPointCountChangeListener) { this.onPointCountChangeListener = onPointCountChangeListener; } public boolean onTouch(View v, MotionEvent event) { addTouchEvent(event); return true; } }