diff options
author | Dianne Hackborn <hackbod@google.com> | 2010-02-11 22:19:06 -0800 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2010-02-12 13:19:06 -0800 |
commit | 90d2db3d21d07c2a4b4cbbc558f5ec59d20098c3 (patch) | |
tree | 51f9e1bcb1cfbfe18899bdb926c375164f3939f7 /common | |
parent | 965e37ec88609c36a3c5461ece459a96abb6f7ca (diff) | |
download | frameworks_base-90d2db3d21d07c2a4b4cbbc558f5ec59d20098c3.zip frameworks_base-90d2db3d21d07c2a4b4cbbc558f5ec59d20098c3.tar.gz frameworks_base-90d2db3d21d07c2a4b4cbbc558f5ec59d20098c3.tar.bz2 |
Add Pointer Location to the window manager.
The window manager now has pointer location built into it.
Viva la touch!
Diffstat (limited to 'common')
-rw-r--r-- | common/java/com/android/common/ui/PointerLocationView.java | 333 |
1 files changed, 333 insertions, 0 deletions
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 0000000..e83c5ae --- /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<Float> mXs = new ArrayList<Float>(); + private final ArrayList<Float> mYs = new ArrayList<Float>(); + 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<PointerState> mPointers + = new ArrayList<PointerState>(); + + 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<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(); + + //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action) + // + " pointers=" + event.getPointerCount()); + + int NP = mPointers.size(); + + //mRect.set(0, 0, getWidth(), mHeaderBottom+1); + //invalidate(mRect); + //if (mCurDown) { + // mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3, + // mCurX+mCurWidth+3, mCurY+mCurWidth+3); + //} else { + // mRect.setEmpty(); + //} + 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) { + final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK) + >> 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<NI; i++) { + final PointerState ps = mPointers.get(event.getPointerId(i)); + 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 " + (i+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 " + (i+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) { + final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK) + >> 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<NI; i++) { + final PointerState ps = mPointers.get(event.getPointerId(i)); + if (ps.mCurDown) { + ps.mCurDown = false; + if (mPrintCoords) { + Log.i("Pointer", "Pointer " + (i+1) + ": UP"); + } + } + } + } + + //if (mCurDown) { + // mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3, + // mCurX+mCurWidth+3, mCurY+mCurWidth+3); + //} + //invalidate(mRect); + postInvalidate(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + addTouchEvent(event); + return true; + } +} |