/* * 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.android.internal.widget; 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_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> 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