PointerLocationView.java revision 80fd47ce75253dcdc2cfa85d7a3f42634b923a47
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; 26c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brownimport android.view.KeyEvent; 2790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.MotionEvent; 2890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.VelocityTracker; 2990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.View; 3090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.ViewConfiguration; 31cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brownimport android.view.MotionEvent.PointerCoords; 3290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport java.util.ArrayList; 3490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornpublic class PointerLocationView extends View { 368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final String TAG = "Pointer"; 378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 3890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public static class PointerState { 398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Trace of previous points. 408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private float[] mTraceX = new float[32]; 418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private float[] mTraceY = new float[32]; 428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mTraceCount; 438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // True if the pointer is down. 4590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent coordinates. 48cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown private PointerCoords mCoords = new PointerCoords(); 498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent velocity. 519e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mXVelocity; 529e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mYVelocity; 538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void clearTrace() { 558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount = 0; 568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void addTrace(float x, float y) { 598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int traceCapacity = mTraceX.length; 608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (mTraceCount == traceCapacity) { 618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown traceCapacity *= 2; 628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceX = new float[traceCapacity]; 638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount); 648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX = newTraceX; 658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceY = new float[traceCapacity]; 678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount); 688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY = newTraceY; 698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX[mTraceCount] = x; 728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY[mTraceCount] = y; 738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount += 1; 748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 7690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 7790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ViewConfiguration mVC; 7890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextPaint; 7990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextBackgroundPaint; 8090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextLevelPaint; 8190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPaint; 8290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTargetPaint; 8390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPathPaint; 8490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final FontMetricsInt mTextMetrics = new FontMetricsInt(); 8590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mHeaderBottom; 8690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 8790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurNumPointers; 8890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mMaxNumPointers; 89d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown private int mActivePointerId; 908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); 91cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown private final PointerCoords mHoverCoords = new PointerCoords(); 9290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 939e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private final VelocityTracker mVelocity; 949e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final FasterStringBuilder mText = new FasterStringBuilder(); 968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 9790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mPrintCoords = true; 9890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 9990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public PointerLocationView(Context c) { 10090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super(c); 101c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown setFocusableInTouchMode(true); 102c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 10390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mVC = ViewConfiguration.get(c); 10490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint = new Paint(); 10590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setAntiAlias(true); 10690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setTextSize(10 10790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn * getResources().getDisplayMetrics().density); 10890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setARGB(255, 0, 0, 0); 10990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint = new Paint(); 11090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setAntiAlias(false); 11190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setARGB(128, 255, 255, 255); 11290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint = new Paint(); 11390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setAntiAlias(false); 11490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setARGB(192, 255, 0, 0); 11590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint = new Paint(); 11690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setAntiAlias(true); 11790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 255, 255, 255); 11890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 11990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(2); 12090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint = new Paint(); 12190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setAntiAlias(false); 12290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setARGB(255, 0, 0, 192); 12390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint = new Paint(); 12490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setAntiAlias(false); 12590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setARGB(255, 0, 96, 255); 12690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 12790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(1); 12890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 12990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 13090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 131d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = 0; 1329e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 1339e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity = VelocityTracker.obtain(); 1348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown logInputDeviceCapabilities(); 1368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 1378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void logInputDeviceCapabilities() { 1398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int[] deviceIds = InputDevice.getDeviceIds(); 1408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i = 0; i < deviceIds.length; i++) { 1418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown InputDevice device = InputDevice.getDevice(deviceIds[i]); 1428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (device != null) { 1438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, device.toString()); 1448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 1458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 14690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 14790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 14890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void setPrintCoords(boolean state) { 14990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPrintCoords = state; 15090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 15190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 15290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 15390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 15490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super.onMeasure(widthMeasureSpec, heightMeasureSpec); 15590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.getFontMetricsInt(mTextMetrics); 15690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; 15790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (false) { 15890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent 15990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " descent=" + mTextMetrics.descent 16090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " leading=" + mTextMetrics.leading 16190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " top=" + mTextMetrics.top 16290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " bottom=" + mTextMetrics.bottom); 16390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 16490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 1658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw an oval. When angle is 0 radians, orients the major axis vertically, 1678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // angles less than or greater than 0 radians rotate the major axis left or right. 1688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private RectF mReusableOvalRect = new RectF(); 1698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void drawOval(Canvas canvas, float x, float y, float major, float minor, 1708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float angle, Paint paint) { 1718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.save(Canvas.MATRIX_SAVE_FLAG); 1725068ad8d2396d6d7bfbdb1c2c3fe57104744f1f9Jeff Brown canvas.rotate((float) (angle * 180 / Math.PI), x, y); 1738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.left = x - minor / 2; 1748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.right = x + minor / 2; 1758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.top = y - major / 2; 1768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.bottom = y + major / 2; 1778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawOval(mReusableOvalRect, paint); 1788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.restore(); 1798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 18090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 18190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 18290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onDraw(Canvas canvas) { 18390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn synchronized (mPointers) { 18490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int w = getWidth(); 18590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int itemW = w/7; 18690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int base = -mTextMetrics.ascent+1; 18790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int bottom = mHeaderBottom; 18890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 18990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final int NP = mPointers.size(); 19090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 1918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Labels 192d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (mActivePointerId >= 0) { 193d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown final PointerState ps = mPointers.get(mActivePointerId); 194d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 19590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); 1968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 1978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("P: ").append(mCurNumPointers) 1988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" / ").append(mMaxNumPointers) 1998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1, base, mTextPaint); 200d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 2018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int N = ps.mTraceCount; 20290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if ((mCurDown && ps.mCurDown) || N == 0) { 20390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); 2048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("X: ").append(ps.mCoords.x, 1) 2068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 20790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); 2088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Y: ").append(ps.mCoords.y, 1) 2108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 21190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } else { 2128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float dx = ps.mTraceX[N - 1] - ps.mTraceX[0]; 2138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float dy = ps.mTraceY[N - 1] - ps.mTraceY[0]; 21490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, 21590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Math.abs(dx) < mVC.getScaledTouchSlop() 21690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ? mTextBackgroundPaint : mTextLevelPaint); 2178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2188d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("dX: ").append(dx, 1) 2198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 22090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, 22190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Math.abs(dy) < mVC.getScaledTouchSlop() 22290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ? mTextBackgroundPaint : mTextLevelPaint); 2238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("dY: ").append(dy, 1) 2258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 22690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 22790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); 2298d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Xv: ").append(ps.mXVelocity, 3) 2318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 3, base, mTextPaint); 23290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 23390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); 2348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Yv: ").append(ps.mYVelocity, 3) 2368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 4, base, mTextPaint); 23790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 23890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); 2398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, 24090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn bottom, mTextLevelPaint); 2418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Prs: ").append(ps.mCoords.pressure, 2) 2438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 5, base, mTextPaint); 24490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 24590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); 2468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCoords.size * itemW) - 1, 24790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn bottom, mTextLevelPaint); 2488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 2498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Size: ").append(ps.mCoords.size, 2) 2508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .toString(), 1 + itemW * 6, base, mTextPaint); 25190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 25290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Pointer trace. 2548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int p = 0; p < NP; p++) { 25590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(p); 25690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw path. 2588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int N = ps.mTraceCount; 2598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float lastX = 0, lastY = 0; 26090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn boolean haveLast = false; 26190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn boolean drawn = false; 26290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 128, 255, 255); 2638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i=0; i < N; i++) { 2648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float x = ps.mTraceX[i]; 2658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float y = ps.mTraceY[i]; 26690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (Float.isNaN(x)) { 26790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn haveLast = false; 26890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn continue; 26990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (haveLast) { 27190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawLine(lastX, lastY, x, y, mPathPaint); 27290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn canvas.drawPoint(lastX, lastY, mPaint); 27390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn drawn = true; 27490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn lastX = x; 27690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn lastY = y; 27790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn haveLast = true; 27890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 27990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 2808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw velocity vector. 28190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (drawn) { 2829e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mPaint.setARGB(255, 255, 64, 128); 2838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float xVel = ps.mXVelocity * (1000 / 60); 2848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float yVel = ps.mYVelocity * (1000 / 60); 2858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); 2868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 2878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (mCurDown && ps.mCurDown) { 2898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw crosshairs. 2908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint); 2918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint); 2928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw current point. 2948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int pressureLevel = (int)(ps.mCoords.pressure * 255); 2958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel); 2968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint); 2978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw current touch ellipse. 2998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128); 3008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor, 3018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint); 3028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 3038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw current tool ellipse. 3048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel); 3058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor, 3068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint); 307517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown 308517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown // Draw the orientation arrow. 309517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown mPaint.setARGB(255, pressureLevel, 255, 0); 310517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown float orientationVectorX = (float) (Math.sin(-ps.mCoords.orientation) 311517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown * ps.mCoords.toolMajor * 0.7); 312517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown float orientationVectorY = (float) (Math.cos(-ps.mCoords.orientation) 313517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown * ps.mCoords.toolMajor * 0.7); 314517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown canvas.drawLine( 315517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown ps.mCoords.x - orientationVectorX, ps.mCoords.y - orientationVectorY, 316517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown ps.mCoords.x + orientationVectorX, ps.mCoords.y + orientationVectorY, 317517bb4c859a2bb8d30316204f39bf5b6c89c3e4dJeff Brown mPaint); 31890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 31990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 32090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 32190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 3228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 323fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown private void logPointerCoords(int action, int index, MotionEvent.PointerCoords coords, int id, 324fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown int toolType, int buttonState) { 32533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final String prefix; 32633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown switch (action & MotionEvent.ACTION_MASK) { 32733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_DOWN: 32833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "DOWN"; 32933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 33033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_UP: 33133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "UP"; 33233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 33333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_MOVE: 33433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 33533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 33633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_CANCEL: 33733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "CANCEL"; 33833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 33933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_OUTSIDE: 34033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "OUTSIDE"; 34133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 34233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_POINTER_DOWN: 34333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 34433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { 34533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "DOWN"; 34633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } else { 34733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 34833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 34933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 35033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_POINTER_UP: 35133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 35233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { 35333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "UP"; 35433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } else { 35533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 35633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 35733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 35833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_HOVER_MOVE: 35933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "HOVER MOVE"; 36033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 361a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown case MotionEvent.ACTION_HOVER_ENTER: 362a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown prefix = "HOVER ENTER"; 363a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown break; 364a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown case MotionEvent.ACTION_HOVER_EXIT: 365a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown prefix = "HOVER EXIT"; 366a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown break; 36733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_SCROLL: 36833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "SCROLL"; 36933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 37033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown default: 37133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = Integer.toString(action); 37233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 37333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 37433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 3758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, mText.clear() 3768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append("Pointer ").append(id + 1) 37733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(": ") 37833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(prefix) 37933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(" (").append(coords.x, 3).append(", ").append(coords.y, 3) 3808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(") Pressure=").append(coords.pressure, 3) 3818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Size=").append(coords.size, 3) 3828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMajor=").append(coords.touchMajor, 3) 3838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMinor=").append(coords.touchMinor, 3) 3848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMajor=").append(coords.toolMajor, 3) 3858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMinor=").append(coords.toolMinor, 3) 3868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) 3876f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append("deg") 38880fd47ce75253dcdc2cfa85d7a3f42634b923a47Jeff Brown .append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1) 3896f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1) 3906f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1) 391fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown .append(" ToolType=").append(MotionEvent.toolTypeToString(toolType)) 392fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown .append(" ButtonState=").append(MotionEvent.buttonStateToString(buttonState)) 3936f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .toString()); 3948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 39590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 39633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown public void addPointerEvent(MotionEvent event) { 39790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn synchronized (mPointers) { 398fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown final int action = event.getAction(); 39990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn int NP = mPointers.size(); 400fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown 4018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_DOWN 4028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { 4038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 4048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down 4058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_DOWN) { 4068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int p=0; p<NP; p++) { 4078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final PointerState ps = mPointers.get(p); 4088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.clearTrace(); 4098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.mCurDown = false; 4108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 4118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mCurDown = true; 41233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown mCurNumPointers = 0; 4138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mMaxNumPointers = 0; 4148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mVelocity.clear(); 41590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 41633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 41733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown mCurNumPointers += 1; 41833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (mMaxNumPointers < mCurNumPointers) { 41933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown mMaxNumPointers = mCurNumPointers; 42033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 42133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 422b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(index); 42390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn while (NP <= id) { 42490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 42590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 42690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn NP++; 42790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 4288d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 429d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (mActivePointerId < 0 || 43033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown !mPointers.get(mActivePointerId).mCurDown) { 431d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = id; 432d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown } 433d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 43490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(id); 43590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = true; 43690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 437cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown 43833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final int NI = event.getPointerCount(); 4399e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 4409e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity.addMovement(event); 4419e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity.computeCurrentVelocity(1); 44233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 44333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final int N = event.getHistorySize(); 44433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown for (int historyPos = 0; historyPos < N; historyPos++) { 44533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown for (int i = 0; i < NI; i++) { 44633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final int id = event.getPointerId(i); 44733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final PointerState ps = mCurDown ? mPointers.get(id) : null; 44833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; 44933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown event.getHistoricalPointerCoords(i, historyPos, coords); 45090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 451fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown logPointerCoords(action, i, coords, id, 452fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown event.getToolType(i), event.getButtonState()); 453cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown } 454cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown if (ps != null) { 45533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown ps.addTrace(coords.x, coords.y); 45690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 45790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 45833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 45933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown for (int i = 0; i < NI; i++) { 46033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final int id = event.getPointerId(i); 46133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final PointerState ps = mCurDown ? mPointers.get(id) : null; 46233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; 463cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown event.getPointerCoords(i, coords); 46490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 465fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown logPointerCoords(action, i, coords, id, 466fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown event.getToolType(i), event.getButtonState()); 467cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown } 468cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown if (ps != null) { 469cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown ps.addTrace(coords.x, coords.y); 470cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown ps.mXVelocity = mVelocity.getXVelocity(id); 471cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown ps.mYVelocity = mVelocity.getYVelocity(id); 47290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 47390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 47433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 4758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_UP 476d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown || action == MotionEvent.ACTION_CANCEL 4778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { 4788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 4798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP 4808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 481b125dc5599468a09d82751cd76152071ae485afbDianne Hackborn final int id = event.getPointerId(index); 48290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn final PointerState ps = mPointers.get(id); 48390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn ps.mCurDown = false; 484d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown 485d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (action == MotionEvent.ACTION_UP 486d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown || action == MotionEvent.ACTION_CANCEL) { 4878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mCurDown = false; 48833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown mCurNumPointers = 0; 4898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } else { 49033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown mCurNumPointers -= 1; 491d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown if (mActivePointerId == id) { 492d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = event.getPointerId(index == 0 ? 1 : 0); 493d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown } 4948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown ps.addTrace(Float.NaN, Float.NaN); 49590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 49690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 497fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown 49890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn postInvalidate(); 49990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 50090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 50190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 50290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 50390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public boolean onTouchEvent(MotionEvent event) { 50433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown addPointerEvent(event); 505c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 506c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) { 507c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown requestFocus(); 508c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 50990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn return true; 51090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 5117d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 5127d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn @Override 51333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown public boolean onGenericMotionEvent(MotionEvent event) { 514c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown final int source = event.getSource(); 515c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 51633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown addPointerEvent(event); 517c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 518c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Joystick: " + event); 519c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) { 520c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Position: " + event); 521c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else { 522c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Generic: " + event); 523c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 524c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 525c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 526c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 527c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown @Override 528c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown public boolean onKeyDown(int keyCode, KeyEvent event) { 529c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (shouldLogKey(keyCode)) { 530c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown final int repeatCount = event.getRepeatCount(); 531c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (repeatCount == 0) { 532c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Down: " + event); 533c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else { 534c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Repeat #" + repeatCount + ": " + event); 535c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 53633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown return true; 53733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 538c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return super.onKeyDown(keyCode, event); 539c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 540c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 541c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown @Override 542c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown public boolean onKeyUp(int keyCode, KeyEvent event) { 543c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (shouldLogKey(keyCode)) { 544c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Up: " + event); 545c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 546c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 547c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return super.onKeyUp(keyCode, event); 548c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 549c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 550c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown private static boolean shouldLogKey(int keyCode) { 551c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown switch (keyCode) { 552c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_UP: 553c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_DOWN: 554c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_LEFT: 555c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_RIGHT: 556c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_CENTER: 557c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 558c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown default: 559c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return KeyEvent.isGamepadButton(keyCode) 560c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown || KeyEvent.isModifierKey(keyCode); 561c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 56233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 56333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 56433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown @Override 5657d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn public boolean onTrackballEvent(MotionEvent event) { 5668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, "Trackball: " + event); 567c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 5687d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn } 5697d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 5708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // HACK 5718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // A quick and dirty string builder implementation optimized for GC. 572d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // Using String.format causes the application grind to a halt when 573d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // more than a couple of pointers are down due to the number of 574d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // temporary objects allocated while formatting strings for drawing or logging. 5758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final class FasterStringBuilder { 5768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private char[] mChars; 5778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mLength; 5788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder() { 5808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = new char[64]; 5818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder clear() { 5848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = 0; 5858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 5868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(String value) { 5898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int valueLength = value.length(); 5908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = reserve(valueLength); 5918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value.getChars(0, valueLength, mChars, index); 5928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += valueLength; 5938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 5948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 5968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value) { 5978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return append(value, 0); 5988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 5998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value, int zeroPadWidth) { 6018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final boolean negative = value < 0; 6028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 6038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = - value; 6048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value < 0) { 6058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("-2147483648"); 6068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 6078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int index = reserve(11); 6118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] chars = mChars; 6128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value == 0) { 6148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 6158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += 1; 6168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 6178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6188d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 6208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '-'; 6218d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int divisor = 1000000000; 6248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int numberWidth = 10; 6258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown while (value < divisor) { 6268d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 6278d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown numberWidth -= 1; 6288d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (numberWidth < zeroPadWidth) { 6298d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 6308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6328d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown do { 6348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int digit = value / divisor; 6358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= digit * divisor; 6368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 6378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = (char) (digit + '0'); 6388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } while (divisor != 0); 6398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = index; 6418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 6428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(float value, int precision) { 6458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int scale = 1; 6468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i = 0; i < precision; i++) { 6478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown scale *= 10; 6488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = (float) (Math.rint(value * scale) / scale); 6508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) value); 6528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (precision != 0) { 6548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("."); 6558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = Math.abs(value); 6568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= Math.floor(value); 6578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) (value * scale), precision); 6588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 6618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown @Override 6648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public String toString() { 6658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return new String(mChars, 0, mLength); 6668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 6688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int reserve(int length) { 6698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldLength = mLength; 6708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newLength = mLength + length; 6718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] oldChars = mChars; 6728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldCapacity = oldChars.length; 6738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (newLength > oldCapacity) { 6748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newCapacity = oldCapacity * 2; 6758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] newChars = new char[newCapacity]; 6768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(oldChars, 0, newChars, 0, oldLength); 6778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = newChars; 6788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return oldLength; 6808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 6818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 68290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn} 683