PointerLocationView.java revision d1e0c371a651f024b3de62a686c56e369e3f361e
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; 228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brownimport android.graphics.RectF; 2390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.graphics.Paint.FontMetricsInt; 2490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.util.Log; 258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brownimport android.view.InputDevice; 2690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.MotionEvent; 2790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.VelocityTracker; 2890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.View; 2990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.ViewConfiguration; 3090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport java.util.ArrayList; 3290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornpublic class PointerLocationView extends View { 348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final String TAG = "Pointer"; 358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 3690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public static class PointerState { 378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Trace of previous points. 388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private float[] mTraceX = new float[32]; 398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private float[] mTraceY = new float[32]; 408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mTraceCount; 418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // True if the pointer is down. 4390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent coordinates. 468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private MotionEvent.PointerCoords mCoords = new MotionEvent.PointerCoords(); 478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent velocity. 499e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mXVelocity; 509e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mYVelocity; 518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void clearTrace() { 538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount = 0; 548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void addTrace(float x, float y) { 578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int traceCapacity = mTraceX.length; 588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (mTraceCount == traceCapacity) { 598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown traceCapacity *= 2; 608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceX = new float[traceCapacity]; 618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount); 628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX = newTraceX; 638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceY = new float[traceCapacity]; 658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount); 668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY = newTraceY; 678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX[mTraceCount] = x; 708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY[mTraceCount] = y; 718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount += 1; 728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 7490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 7590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ViewConfiguration mVC; 7690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextPaint; 7790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextBackgroundPaint; 7890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextLevelPaint; 7990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPaint; 8090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTargetPaint; 8190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPathPaint; 8290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final FontMetricsInt mTextMetrics = new FontMetricsInt(); 8390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mHeaderBottom; 8490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 8590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurNumPointers; 8690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mMaxNumPointers; 87d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown private int mActivePointerId; 888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); 8990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 909e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private final VelocityTracker mVelocity; 919e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final FasterStringBuilder mText = new FasterStringBuilder(); 938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 9490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mPrintCoords = true; 9590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 9690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public PointerLocationView(Context c) { 9790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super(c); 987d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn setFocusable(true); 9990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mVC = ViewConfiguration.get(c); 10090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint = new Paint(); 10190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setAntiAlias(true); 10290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setTextSize(10 10390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn * getResources().getDisplayMetrics().density); 10490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setARGB(255, 0, 0, 0); 10590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint = new Paint(); 10690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setAntiAlias(false); 10790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setARGB(128, 255, 255, 255); 10890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint = new Paint(); 10990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setAntiAlias(false); 11090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setARGB(192, 255, 0, 0); 11190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint = new Paint(); 11290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setAntiAlias(true); 11390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 255, 255, 255); 11490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 11590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(2); 11690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint = new Paint(); 11790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setAntiAlias(false); 11890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setARGB(255, 0, 0, 192); 11990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint = new Paint(); 12090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setAntiAlias(false); 12190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setARGB(255, 0, 96, 255); 12290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 12390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(1); 12490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 12590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 12690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 127d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = 0; 1289e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 1299e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity = VelocityTracker.obtain(); 1308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown logInputDeviceCapabilities(); 1328d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 1338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void logInputDeviceCapabilities() { 1358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int[] deviceIds = InputDevice.getDeviceIds(); 1368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i = 0; i < deviceIds.length; i++) { 1378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown InputDevice device = InputDevice.getDevice(deviceIds[i]); 1388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (device != null) { 1398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, device.toString()); 1408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 1418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 14290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 14390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 14490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void setPrintCoords(boolean state) { 14590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPrintCoords = state; 14690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 14790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 14890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 14990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 15090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super.onMeasure(widthMeasureSpec, heightMeasureSpec); 15190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.getFontMetricsInt(mTextMetrics); 15290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; 15390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (false) { 15490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent 15590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " descent=" + mTextMetrics.descent 15690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " leading=" + mTextMetrics.leading 15790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " top=" + mTextMetrics.top 15890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " bottom=" + mTextMetrics.bottom); 15990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 16090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 1618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw an oval. When angle is 0 radians, orients the major axis vertically, 1638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // angles less than or greater than 0 radians rotate the major axis left or right. 1648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private RectF mReusableOvalRect = new RectF(); 1658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void drawOval(Canvas canvas, float x, float y, float major, float minor, 1668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float angle, Paint paint) { 1678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.save(Canvas.MATRIX_SAVE_FLAG); 1688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.rotate((float) (angle * 180 / Math.PI), x, y); 1698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.left = x - minor / 2; 1708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.right = x + minor / 2; 1718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.top = y - major / 2; 1728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.bottom = y + major / 2; 1738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawOval(mReusableOvalRect, paint); 1748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.restore(); 1758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 17690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 17790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 17890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onDraw(Canvas canvas) { 17990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn synchronized (mPointers) { 18090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int w = getWidth(); 18190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int itemW = w/7; 18290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int base = -mTextMetrics.ascent+1; 18390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int bottom = mHeaderBottom; 18490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 18590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int NP = mPointers.size(); 18690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 1878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Labels 188d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (mActivePointerId >= 0) { 189d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown final PointerState ps = mPointers.get(mActivePointerId); 190d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 19190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); 1928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 1938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("P: ").append(mCurNumPointers) 1948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" / ").append(mMaxNumPointers) 1958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1, base, mTextPaint); 196d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 1978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int N = ps.mTraceCount; 19890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if ((mCurDown && ps.mCurDown) || N == 0) { 19990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); 2008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("X: ").append(ps.mCoords.x, 1) 2028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 20390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); 2048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Y: ").append(ps.mCoords.y, 1) 2068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 20790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } else { 2088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float dx = ps.mTraceX[N - 1] - ps.mTraceX[0]; 2098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float dy = ps.mTraceY[N - 1] - ps.mTraceY[0]; 21090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, 21190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Math.abs(dx) < mVC.getScaledTouchSlop() 21290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ? mTextBackgroundPaint : mTextLevelPaint); 2138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("dX: ").append(dx, 1) 2158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 21690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, 21790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Math.abs(dy) < mVC.getScaledTouchSlop() 21890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ? mTextBackgroundPaint : mTextLevelPaint); 2198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("dY: ").append(dy, 1) 2218d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 22290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 22390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); 2258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2268d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Xv: ").append(ps.mXVelocity, 3) 2278d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 3, base, mTextPaint); 22890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); 2308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Yv: ").append(ps.mYVelocity, 3) 2328d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 4, base, mTextPaint); 23390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 23490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); 2358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, 23690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn bottom, mTextLevelPaint); 2378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Prs: ").append(ps.mCoords.pressure, 2) 2398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 5, base, mTextPaint); 24090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 24190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); 2428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCoords.size * itemW) - 1, 24390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn bottom, mTextLevelPaint); 2448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Size: ").append(ps.mCoords.size, 2) 2468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 6, base, mTextPaint); 24790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 24890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Pointer trace. 2508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int p = 0; p < NP; p++) { 25190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(p); 25290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw path. 2548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int N = ps.mTraceCount; 2558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float lastX = 0, lastY = 0; 25690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn boolean haveLast = false; 25790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn boolean drawn = false; 25890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 128, 255, 255); 2598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i=0; i < N; i++) { 2608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float x = ps.mTraceX[i]; 2618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float y = ps.mTraceY[i]; 26290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (Float.isNaN(x)) { 26390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn haveLast = false; 26490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn continue; 26590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 26690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (haveLast) { 26790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawLine(lastX, lastY, x, y, mPathPaint); 26890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawPoint(lastX, lastY, mPaint); 26990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn drawn = true; 27090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn lastX = x; 27290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn lastY = y; 27390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn haveLast = true; 27490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw velocity vector. 27790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (drawn) { 2789e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mPaint.setARGB(255, 255, 64, 128); 2798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float xVel = ps.mXVelocity * (1000 / 60); 2808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float yVel = ps.mYVelocity * (1000 / 60); 2818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); 2828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 2838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (mCurDown && ps.mCurDown) { 2858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw crosshairs. 2868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint); 2878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint); 2888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw current point. 2908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int pressureLevel = (int)(ps.mCoords.pressure * 255); 2918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel); 2928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint); 2938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw current touch ellipse. 2958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128); 2968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor, 2978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint); 2988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw current tool ellipse. 3008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel); 3018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor, 3028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint); 30390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 30490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 30590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 30690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 3088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void logPointerCoords(MotionEvent.PointerCoords coords, int id) { 3098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, mText.clear() 3108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Pointer ").append(id + 1) 3118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(": (").append(coords.x, 3).append(", ").append(coords.y, 3) 3128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(") Pressure=").append(coords.pressure, 3) 3138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Size=").append(coords.size, 3) 3148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMajor=").append(coords.touchMajor, 3) 3158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMinor=").append(coords.touchMinor, 3) 3168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMajor=").append(coords.toolMajor, 3) 3178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMinor=").append(coords.toolMinor, 3) 3188d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) 3198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("deg").toString()); 3208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 32190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 32290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void addTouchEvent(MotionEvent event) { 32390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn synchronized (mPointers) { 32490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int action = event.getAction(); 32590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3268d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown //Log.i(TAG, "Motion: action=0x" + Integer.toHexString(action) 32790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // + " pointers=" + event.getPointerCount()); 32890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 32990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int NP = mPointers.size(); 33090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 33190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //mRect.set(0, 0, getWidth(), mHeaderBottom+1); 33290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //invalidate(mRect); 33390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //if (mCurDown) { 33490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3, 33590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mCurX+mCurWidth+3, mCurY+mCurWidth+3); 33690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //} else { 33790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mRect.setEmpty(); 33890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //} 3398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_DOWN 3408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { 3418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 3428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down 3438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_DOWN) { 3448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int p=0; p<NP; p++) { 3458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final PointerState ps = mPointers.get(p); 3468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.clearTrace(); 3478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.mCurDown = false; 3488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 3498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mCurDown = true; 3508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mMaxNumPointers = 0; 3518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mVelocity.clear(); 35290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 354b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(index); 35590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn while (NP <= id) { 35690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 35790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 35890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn NP++; 35990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 361d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (mActivePointerId < 0 || 362d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown ! mPointers.get(mActivePointerId).mCurDown) { 363d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = id; 364d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown } 365d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 36690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(id); 36790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = true; 36890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 3698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, mText.clear().append("Pointer ") 3708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(id + 1).append(": DOWN").toString()); 37190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 37290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 37390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 37490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int NI = event.getPointerCount(); 37590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 37690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mCurDown = action != MotionEvent.ACTION_UP 37790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn && action != MotionEvent.ACTION_CANCEL; 37890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mCurNumPointers = mCurDown ? NI : 0; 37990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mMaxNumPointers < mCurNumPointers) { 38090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mMaxNumPointers = mCurNumPointers; 38190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3829e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 3839e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity.addMovement(event); 3849e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity.computeCurrentVelocity(1); 38590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 38690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int i=0; i<NI; i++) { 387b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(i); 388b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final PointerState ps = mPointers.get(id); 38990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int N = event.getHistorySize(); 39090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn for (int j=0; j<N; j++) { 3918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown event.getHistoricalPointerCoords(i, j, ps.mCoords); 39290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 3938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown logPointerCoords(ps.mCoords, id); 39490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j)); 39690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown event.getPointerCoords(i, ps.mCoords); 39890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 3998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown logPointerCoords(ps.mCoords, id); 40090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 4018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.addTrace(ps.mCoords.x, ps.mCoords.y); 4029e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown ps.mXVelocity = mVelocity.getXVelocity(id); 4039e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown ps.mYVelocity = mVelocity.getYVelocity(id); 40490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 40590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 4068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_UP 407d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown || action == MotionEvent.ACTION_CANCEL 4088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { 4098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 4108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP 4118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 412b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(index); 41390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(id); 41490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = false; 41590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 4168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, mText.clear().append("Pointer ") 4178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(id + 1).append(": UP").toString()); 41890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 419d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 420d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (action == MotionEvent.ACTION_UP 421d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown || action == MotionEvent.ACTION_CANCEL) { 4228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mCurDown = false; 4238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } else { 424d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (mActivePointerId == id) { 425d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = event.getPointerId(index == 0 ? 1 : 0); 426d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown } 4278d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.addTrace(Float.NaN, Float.NaN); 42890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 42990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 43090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 43190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //if (mCurDown) { 43290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3, 43390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn // mCurX+mCurWidth+3, mCurY+mCurWidth+3); 43490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //} 43590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn //invalidate(mRect); 43690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn postInvalidate(); 43790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 43890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 43990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 44090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 44190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public boolean onTouchEvent(MotionEvent event) { 44290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn addTouchEvent(event); 44390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn return true; 44490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 4457d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 4467d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn @Override 4477d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn public boolean onTrackballEvent(MotionEvent event) { 4488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, "Trackball: " + event); 4497d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn return super.onTrackballEvent(event); 4507d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn } 4517d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 4528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // HACK 4538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // A quick and dirty string builder implementation optimized for GC. 454d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // Using String.format causes the application grind to a halt when 455d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // more than a couple of pointers are down due to the number of 456d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // temporary objects allocated while formatting strings for drawing or logging. 4578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final class FasterStringBuilder { 4588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private char[] mChars; 4598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mLength; 4608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder() { 4628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = new char[64]; 4638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder clear() { 4668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = 0; 4678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 4688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(String value) { 4718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int valueLength = value.length(); 4728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = reserve(valueLength); 4738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value.getChars(0, valueLength, mChars, index); 4748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += valueLength; 4758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 4768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value) { 4798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return append(value, 0); 4808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value, int zeroPadWidth) { 4838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final boolean negative = value < 0; 4848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 4858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = - value; 4868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value < 0) { 4878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("-2147483648"); 4888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 4898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int index = reserve(11); 4938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] chars = mChars; 4948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 4958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value == 0) { 4968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 4978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += 1; 4988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 4998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 5028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '-'; 5038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int divisor = 1000000000; 5068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int numberWidth = 10; 5078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown while (value < divisor) { 5088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 5098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown numberWidth -= 1; 5108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (numberWidth < zeroPadWidth) { 5118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 5128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown do { 5168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int digit = value / divisor; 5178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= digit * divisor; 5188d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 5198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = (char) (digit + '0'); 5208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } while (divisor != 0); 5218d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = index; 5238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 5248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5268d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(float value, int precision) { 5278d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int scale = 1; 5288d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i = 0; i < precision; i++) { 5298d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown scale *= 10; 5308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = (float) (Math.rint(value * scale) / scale); 5328d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) value); 5348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (precision != 0) { 5368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("."); 5378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = Math.abs(value); 5388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= Math.floor(value); 5398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) (value * scale), precision); 5408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 5438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown @Override 5468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public String toString() { 5478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return new String(mChars, 0, mLength); 5488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int reserve(int length) { 5518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldLength = mLength; 5528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newLength = mLength + length; 5538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] oldChars = mChars; 5548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldCapacity = oldChars.length; 5558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (newLength > oldCapacity) { 5568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newCapacity = oldCapacity * 2; 5578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] newChars = new char[newCapacity]; 5588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(oldChars, 0, newChars, 0, oldLength); 5598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = newChars; 5608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return oldLength; 5628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 56490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn} 565