diff --git a/common/java/com/android/common/ui/PointerLocationView.java b/common/java/com/android/common/ui/PointerLocationView.java new file mode 100644 index 000000000..e83c5ae35 --- /dev/null +++ b/common/java/com/android/common/ui/PointerLocationView.java @@ -0,0 +1,333 @@ +package com.android.common.ui; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.FontMetricsInt; +import android.util.Log; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; + +import java.util.ArrayList; + +public class PointerLocationView extends View { + 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 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 c) { + super(c); + mVC = ViewConfiguration.get(c); + mTextPaint = new Paint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setTextSize(10 + * getResources().getDisplayMetrics().density); + mTextPaint.setARGB(255, 0, 0, 0); + 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; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mTextPaint.getFontMetricsInt(mTextMetrics); + mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; + if (false) { + Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent + + " descent=" + mTextMetrics.descent + + " leading=" + mTextMetrics.leading + + " top=" + mTextMetrics.top + + " bottom=" + mTextMetrics.bottom); + } + } + + @Override + protected void onDraw(Canvas canvas) { + synchronized (mPointers) { + final int w = getWidth(); + final int itemW = w/7; + final int base = -mTextMetrics.ascent+1; + final int bottom = mHeaderBottom; + + final int NP = mPointers.size(); + + 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); + } + + for (int p=0; p> MotionEvent.ACTION_POINTER_ID_SHIFT; + 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> MotionEvent.ACTION_POINTER_ID_SHIFT; + 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