PointerLocationView.java revision 7d9af5ae762c59e879a86e77dcb330856774bc09
1f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root/* 2f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * Copyright (C) 2010 The Android Open Source Project 3f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * 4f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * you may not use this file except in compliance with the License. 6f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * You may obtain a copy of the License at 7f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * 8f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * http://www.apache.org/licenses/LICENSE-2.0 9f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * 10f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * Unless required by applicable law or agreed to in writing, software 11f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * See the License for the specific language governing permissions and 14f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root * limitations under the License. 15f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root */ 16f8d0f095e34f8d661ca5b7d555d8610272099bffKenny Root 17829778843cf459384841f9f4ecafe862b6228d6eDianne Hackbornpackage com.android.internal.widget; 1890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 1990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.content.Context; 2090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.graphics.Canvas; 2190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.graphics.Paint; 2290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.graphics.Paint.FontMetricsInt; 2390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.util.Log; 2490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.MotionEvent; 2590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.VelocityTracker; 2690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.View; 2790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.ViewConfiguration; 2890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport java.util.ArrayList; 3090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornpublic class PointerLocationView extends View { 3290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public static class PointerState { 3390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ArrayList<Float> mXs = new ArrayList<Float>(); 3490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ArrayList<Float> mYs = new ArrayList<Float>(); 3590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 3690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurX; 3790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurY; 3890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private float mCurPressure; 3990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private float mCurSize; 4090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurWidth; 4190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private VelocityTracker mVelocity; 4290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 4390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 4490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ViewConfiguration mVC; 4590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextPaint; 4690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextBackgroundPaint; 4790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextLevelPaint; 4890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPaint; 4990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTargetPaint; 5090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPathPaint; 5190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final FontMetricsInt mTextMetrics = new FontMetricsInt(); 5290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mHeaderBottom; 5390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 5490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurNumPointers; 5590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mMaxNumPointers; 5690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ArrayList<PointerState> mPointers 5790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn = new ArrayList<PointerState>(); 5890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 5990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mPrintCoords = true; 6090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 6190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public PointerLocationView(Context c) { 6290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super(c); 637d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn setFocusable(true); 6490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mVC = ViewConfiguration.get(c); 6590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint = new Paint(); 6690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setAntiAlias(true); 6790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setTextSize(10 6890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn * getResources().getDisplayMetrics().density); 6990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setARGB(255, 0, 0, 0); 7090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint = new Paint(); 7190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setAntiAlias(false); 7290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setARGB(128, 255, 255, 255); 7390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint = new Paint(); 7490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setAntiAlias(false); 7590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setARGB(192, 255, 0, 0); 7690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint = new Paint(); 7790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setAntiAlias(true); 7890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 255, 255, 255); 7990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 8090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(2); 8190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint = new Paint(); 8290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setAntiAlias(false); 8390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setARGB(255, 0, 0, 192); 8490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint = new Paint(); 8590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setAntiAlias(false); 8690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setARGB(255, 0, 96, 255); 8790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 8890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(1); 8990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 9090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 9190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mVelocity = VelocityTracker.obtain(); 9290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 9390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 9490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 9590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void setPrintCoords(boolean state) { 9690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPrintCoords = state; 9790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 9890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 9990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 10090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 10190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super.onMeasure(widthMeasureSpec, heightMeasureSpec); 10290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.getFontMetricsInt(mTextMetrics); 10390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; 10490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (false) { 10590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent 10690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " descent=" + mTextMetrics.descent 10790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " leading=" + mTextMetrics.leading 10890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " top=" + mTextMetrics.top 10990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " bottom=" + mTextMetrics.bottom); 11090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 11190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 11290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 11390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 11490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onDraw(Canvas canvas) { 11590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn synchronized (mPointers) { 11690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int w = getWidth(); 11790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int itemW = w/7; 11890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int base = -mTextMetrics.ascent+1; 11990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int bottom = mHeaderBottom; 12090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 12190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int NP = mPointers.size(); 12290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 12390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (NP > 0) { 12490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(0); 12590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); 12690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("P: " + mCurNumPointers + " / " + mMaxNumPointers, 12790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 1, base, mTextPaint); 12890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 12990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int N = ps.mXs.size(); 13090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if ((mCurDown && ps.mCurDown) || N == 0) { 13190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); 13290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("X: " + ps.mCurX, 1 + itemW, base, mTextPaint); 13390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); 13490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base, mTextPaint); 13590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } else { 13690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float dx = ps.mXs.get(N-1) - ps.mXs.get(0); 13790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float dy = ps.mYs.get(N-1) - ps.mYs.get(0); 13890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, 13990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Math.abs(dx) < mVC.getScaledTouchSlop() 14090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ? mTextBackgroundPaint : mTextLevelPaint); 14190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("dX: " + String.format("%.1f", dx), 1 + itemW, base, mTextPaint); 14290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, 14390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Math.abs(dy) < mVC.getScaledTouchSlop() 14490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ? mTextBackgroundPaint : mTextLevelPaint); 14590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("dY: " + String.format("%.1f", dy), 1 + itemW * 2, base, mTextPaint); 14690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 14790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 14890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); 14990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getXVelocity() * 1000); 15090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, mTextPaint); 15190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 15290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); 15390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getYVelocity() * 1000); 15490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, mTextPaint); 15590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 15690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); 15790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCurPressure * itemW) - 1, 15890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn bottom, mTextLevelPaint); 15990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), 1 + itemW * 5, 16090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn base, mTextPaint); 16190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 16290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); 16390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) - 1, 16490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn bottom, mTextLevelPaint); 16590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize), 1 + itemW * 6, 16690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn base, mTextPaint); 16790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 16890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 16990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int p=0; p<NP; p++) { 17090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(p); 17190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 17290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mCurDown && ps.mCurDown) { 17390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawLine(0, (int)ps.mCurY, getWidth(), (int)ps.mCurY, mTargetPaint); 17490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawLine((int)ps.mCurX, 0, (int)ps.mCurX, getHeight(), mTargetPaint); 17590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int pressureLevel = (int)(ps.mCurPressure*255); 17690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel); 17790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint); 17890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint); 17990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 18090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 18190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 18290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int p=0; p<NP; p++) { 18390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(p); 18490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 18590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int N = ps.mXs.size(); 18690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float lastX=0, lastY=0; 18790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn boolean haveLast = false; 18890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn boolean drawn = false; 18990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 128, 255, 255); 19090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int i=0; i<N; i++) { 19190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float x = ps.mXs.get(i); 19290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float y = ps.mYs.get(i); 19390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (Float.isNaN(x)) { 19490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn haveLast = false; 19590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn continue; 19690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 19790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (haveLast) { 19890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawLine(lastX, lastY, x, y, mPathPaint); 19990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawPoint(lastX, lastY, mPaint); 20090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn drawn = true; 20190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 20290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn lastX = x; 20390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn lastY = y; 20490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn haveLast = true; 20590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 20690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 20790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (drawn) { 20890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (ps.mVelocity != null) { 20990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 255, 64, 128); 21090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float xVel = ps.mVelocity.getXVelocity() * (1000/60); 21190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn float yVel = ps.mVelocity.getYVelocity() * (1000/60); 21290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint); 21390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } else { 21490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawPoint(lastX, lastY, mPaint); 21590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 21690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 21790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 21890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 21990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 22090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void addTouchEvent(MotionEvent event) { 22290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn synchronized (mPointers) { 22390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int action = event.getAction(); 22490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action) 22690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // + " pointers=" + event.getPointerCount()); 22790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int NP = mPointers.size(); 22990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 23090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //mRect.set(0, 0, getWidth(), mHeaderBottom+1); 23190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //invalidate(mRect); 23290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //if (mCurDown) { 23390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3, 23490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mCurX+mCurWidth+3, mCurY+mCurWidth+3); 23590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //} else { 23690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mRect.setEmpty(); 23790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //} 23890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (action == MotionEvent.ACTION_DOWN) { 23990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int p=0; p<NP; p++) { 24090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(p); 24190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mXs.clear(); 24290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mYs.clear(); 24390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mVelocity = VelocityTracker.obtain(); 24490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = false; 24590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 24690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.get(0).mCurDown = true; 24790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mMaxNumPointers = 0; 24890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 24990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("Pointer", "Pointer 1: DOWN"); 25090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 25190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 25290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 25390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { 254b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK) 255b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 256b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(index); 25790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn while (NP <= id) { 25890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 25990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mVelocity = VelocityTracker.obtain(); 26090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 26190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn NP++; 26290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 26390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(id); 26490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mVelocity = VelocityTracker.obtain(); 26590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = true; 26690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 26790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("Pointer", "Pointer " + (id+1) + ": DOWN"); 26890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 26990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 27190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int NI = event.getPointerCount(); 27290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 27390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mCurDown = action != MotionEvent.ACTION_UP 27490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn && action != MotionEvent.ACTION_CANCEL; 27590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mCurNumPointers = mCurDown ? NI : 0; 27690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mMaxNumPointers < mCurNumPointers) { 27790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mMaxNumPointers = mCurNumPointers; 27890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 28090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int i=0; i<NI; i++) { 281b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(i); 282b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final PointerState ps = mPointers.get(id); 28390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mVelocity.addMovement(event); 28490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mVelocity.computeCurrentVelocity(1); 28590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int N = event.getHistorySize(); 28690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int j=0; j<N; j++) { 28790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 288b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn Log.i("Pointer", "Pointer " + (id+1) + ": (" 28990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + event.getHistoricalX(i, j) 29090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + ", " + event.getHistoricalY(i, j) + ")" 29190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " Prs=" + event.getHistoricalPressure(i, j) 29290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " Size=" + event.getHistoricalSize(i, j)); 29390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 29490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mXs.add(event.getHistoricalX(i, j)); 29590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mYs.add(event.getHistoricalY(i, j)); 29690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 29790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 298b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn Log.i("Pointer", "Pointer " + (id+1) + ": (" 29990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + event.getX(i) + ", " + event.getY(i) + ")" 30090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " Prs=" + event.getPressure(i) 30190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " Size=" + event.getSize(i)); 30290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 30390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mXs.add(event.getX(i)); 30490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mYs.add(event.getY(i)); 30590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurX = (int)event.getX(i); 30690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurY = (int)event.getY(i); 30790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX 30890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // + "," + ps.mCurY + ")"); 30990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurPressure = event.getPressure(i); 31090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurSize = event.getSize(i); 31190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurWidth = (int)(ps.mCurSize*(getWidth()/3)); 31290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 31390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 31490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { 315b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK) 316b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 317b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(index); 31890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(id); 31990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mXs.add(Float.NaN); 32090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mYs.add(Float.NaN); 32190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = false; 32290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 32390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("Pointer", "Pointer " + (id+1) + ": UP"); 32490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 32590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 32690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 32790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (action == MotionEvent.ACTION_UP) { 32890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int i=0; i<NI; i++) { 329b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(i); 330b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final PointerState ps = mPointers.get(id); 33190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (ps.mCurDown) { 33290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = false; 33390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 334b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn Log.i("Pointer", "Pointer " + (id+1) + ": UP"); 33590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 33690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 33790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 33890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 33990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 34090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //if (mCurDown) { 34190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3, 34290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mCurX+mCurWidth+3, mCurY+mCurWidth+3); 34390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //} 34490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //invalidate(mRect); 34590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn postInvalidate(); 34690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 34790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 34890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 34990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 35090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public boolean onTouchEvent(MotionEvent event) { 35190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn addTouchEvent(event); 35290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn return true; 35390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3547d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 3557d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn @Override 3567d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn public boolean onTrackballEvent(MotionEvent event) { 3577d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn Log.i("Pointer", "Trackball: " + event); 3587d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn return super.onTrackballEvent(event); 3597d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn } 3607d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 36190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn} 362