PointerLocationView.java revision 2f1cd7e68bc1f45243191f63984523ba6d36b590
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; 24af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brownimport android.hardware.input.InputManager; 25af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brownimport android.hardware.input.InputManager.InputDeviceListener; 269eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brownimport android.os.SystemProperties; 2790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.util.Log; 288d60866e2100db70ecf0502c14768a384514d7e9Jeff Brownimport android.view.InputDevice; 29c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brownimport android.view.KeyEvent; 3090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.MotionEvent; 3190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.VelocityTracker; 3290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.View; 3390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport android.view.ViewConfiguration; 34cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brownimport android.view.MotionEvent.PointerCoords; 3590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 3690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackbornimport java.util.ArrayList; 3790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 38af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brownpublic class PointerLocationView extends View implements InputDeviceListener { 398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final String TAG = "Pointer"; 409eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 419eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown // The system property key used to specify an alternate velocity tracker strategy 429eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown // to plot alongside the default one. Useful for testing and comparison purposes. 439eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private static final String ALT_STRATEGY_PROPERY_KEY = "debug.velocitytracker.alt"; 449eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 4590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public static class PointerState { 468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Trace of previous points. 478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private float[] mTraceX = new float[32]; 488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private float[] mTraceY = new float[32]; 498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mTraceCount; 508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // True if the pointer is down. 5290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent coordinates. 55cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown private PointerCoords mCoords = new PointerCoords(); 5665fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private int mToolType; 578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent velocity. 599e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mXVelocity; 609e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mYVelocity; 619eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private float mAltXVelocity; 629eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private float mAltYVelocity; 63b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown 6486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright // Current bounding box, if any 6586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private boolean mHasBoundingBox; 6686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingLeft; 6786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingTop; 6886172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingRight; 6986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingBottom; 7086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright 71b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown // Position estimator. 72b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private VelocityTracker.Estimator mEstimator = new VelocityTracker.Estimator(); 739eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private VelocityTracker.Estimator mAltEstimator = new VelocityTracker.Estimator(); 74b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown 758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void clearTrace() { 768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount = 0; 778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void addTrace(float x, float y) { 808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int traceCapacity = mTraceX.length; 818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (mTraceCount == traceCapacity) { 828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown traceCapacity *= 2; 838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceX = new float[traceCapacity]; 848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount); 858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX = newTraceX; 868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceY = new float[traceCapacity]; 888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount); 898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY = newTraceY; 908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX[mTraceCount] = x; 938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY[mTraceCount] = y; 948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount += 1; 958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 9690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 9790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 98b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private final int ESTIMATE_PAST_POINTS = 4; 99b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private final int ESTIMATE_FUTURE_POINTS = 2; 100b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private final float ESTIMATE_INTERVAL = 0.02f; 101b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown 102af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown private final InputManager mIm; 103af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 10490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ViewConfiguration mVC; 10590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextPaint; 10690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextBackgroundPaint; 10790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextLevelPaint; 10890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPaint; 10990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTargetPaint; 11090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPathPaint; 11190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final FontMetricsInt mTextMetrics = new FontMetricsInt(); 11290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mHeaderBottom; 11390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 11490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurNumPointers; 11590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mMaxNumPointers; 116d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown private int mActivePointerId; 1178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); 11865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private final PointerCoords mTempCoords = new PointerCoords(); 11990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 1209e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private final VelocityTracker mVelocity; 1219eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private final VelocityTracker mAltVelocity; 1229eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 1238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final FasterStringBuilder mText = new FasterStringBuilder(); 1248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 12590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mPrintCoords = true; 12690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 12790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public PointerLocationView(Context c) { 12890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super(c); 129c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown setFocusableInTouchMode(true); 130c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 131af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown mIm = (InputManager)c.getSystemService(Context.INPUT_SERVICE); 132af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 13390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mVC = ViewConfiguration.get(c); 13490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint = new Paint(); 13590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setAntiAlias(true); 13690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setTextSize(10 13790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn * getResources().getDisplayMetrics().density); 13890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setARGB(255, 0, 0, 0); 13990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint = new Paint(); 14090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setAntiAlias(false); 14190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setARGB(128, 255, 255, 255); 14290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint = new Paint(); 14390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setAntiAlias(false); 14490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setARGB(192, 255, 0, 0); 14590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint = new Paint(); 14690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setAntiAlias(true); 14790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 255, 255, 255); 14890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 14990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(2); 15090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint = new Paint(); 15190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setAntiAlias(false); 15290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setARGB(255, 0, 0, 192); 15390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint = new Paint(); 15490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setAntiAlias(false); 15590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setARGB(255, 0, 96, 255); 15690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 15790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(1); 15890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 15990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 16090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 161d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = 0; 1629e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 1639e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity = VelocityTracker.obtain(); 1649eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 1659eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown String altStrategy = SystemProperties.get(ALT_STRATEGY_PROPERY_KEY); 1669eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (altStrategy.length() != 0) { 1679eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown Log.d(TAG, "Comparing default velocity tracker strategy with " + altStrategy); 1689eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity = VelocityTracker.obtain(altStrategy); 1699eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } else { 1709eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity = null; 1719eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 17290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 17390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 17490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void setPrintCoords(boolean state) { 17590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPrintCoords = state; 17690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 17790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 17890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 17990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 18090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super.onMeasure(widthMeasureSpec, heightMeasureSpec); 18190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.getFontMetricsInt(mTextMetrics); 18290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; 18390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (false) { 18490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent 18590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " descent=" + mTextMetrics.descent 18690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " leading=" + mTextMetrics.leading 18790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " top=" + mTextMetrics.top 18890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " bottom=" + mTextMetrics.bottom); 18990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 19090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 1918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 1928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw an oval. When angle is 0 radians, orients the major axis vertically, 1938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // angles less than or greater than 0 radians rotate the major axis left or right. 1948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private RectF mReusableOvalRect = new RectF(); 1958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void drawOval(Canvas canvas, float x, float y, float major, float minor, 1968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float angle, Paint paint) { 1978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.save(Canvas.MATRIX_SAVE_FLAG); 1985068ad8d2396d6d7bfbdb1c2c3fe57104744f1f9Jeff Brown canvas.rotate((float) (angle * 180 / Math.PI), x, y); 1998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.left = x - minor / 2; 2008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.right = x + minor / 2; 2018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.top = y - major / 2; 2028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.bottom = y + major / 2; 2038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawOval(mReusableOvalRect, paint); 2048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.restore(); 2058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 20690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 20790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 20890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onDraw(Canvas canvas) { 20970825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int w = getWidth(); 21070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int itemW = w/7; 21170825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int base = -mTextMetrics.ascent+1; 21270825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int bottom = mHeaderBottom; 21370825161b5bf51ed48319e142751a9c88b104994Jeff Brown 21470825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int NP = mPointers.size(); 21570825161b5bf51ed48319e142751a9c88b104994Jeff Brown 21670825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Labels 21770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mActivePointerId >= 0) { 21870825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(mActivePointerId); 21990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 22070825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); 22170825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 22270825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("P: ").append(mCurNumPointers) 22370825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append(" / ").append(mMaxNumPointers) 22470825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1, base, mTextPaint); 22570825161b5bf51ed48319e142751a9c88b104994Jeff Brown 22670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int N = ps.mTraceCount; 22770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if ((mCurDown && ps.mCurDown) || N == 0) { 22870825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); 2298d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 23070825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("X: ").append(ps.mCoords.x, 1) 23170825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 23270825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); 2338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 23470825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Y: ").append(ps.mCoords.y, 1) 23570825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 23670825161b5bf51ed48319e142751a9c88b104994Jeff Brown } else { 23770825161b5bf51ed48319e142751a9c88b104994Jeff Brown float dx = ps.mTraceX[N - 1] - ps.mTraceX[0]; 23870825161b5bf51ed48319e142751a9c88b104994Jeff Brown float dy = ps.mTraceY[N - 1] - ps.mTraceY[0]; 23970825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, 24070825161b5bf51ed48319e142751a9c88b104994Jeff Brown Math.abs(dx) < mVC.getScaledTouchSlop() 24170825161b5bf51ed48319e142751a9c88b104994Jeff Brown ? mTextBackgroundPaint : mTextLevelPaint); 2428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 24370825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("dX: ").append(dx, 1) 24470825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 24570825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, 24670825161b5bf51ed48319e142751a9c88b104994Jeff Brown Math.abs(dy) < mVC.getScaledTouchSlop() 24770825161b5bf51ed48319e142751a9c88b104994Jeff Brown ? mTextBackgroundPaint : mTextLevelPaint); 2488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 24970825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("dY: ").append(dy, 1) 25070825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 25190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 25270825161b5bf51ed48319e142751a9c88b104994Jeff Brown 25370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); 25470825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 25570825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Xv: ").append(ps.mXVelocity, 3) 25670825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 3, base, mTextPaint); 25770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 25870825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); 25970825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 26070825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Yv: ").append(ps.mYVelocity, 3) 26170825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 4, base, mTextPaint); 26270825161b5bf51ed48319e142751a9c88b104994Jeff Brown 26370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); 26470825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, 26570825161b5bf51ed48319e142751a9c88b104994Jeff Brown bottom, mTextLevelPaint); 26670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 26770825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Prs: ").append(ps.mCoords.pressure, 2) 26870825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 5, base, mTextPaint); 26970825161b5bf51ed48319e142751a9c88b104994Jeff Brown 27070825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); 27170825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCoords.size * itemW) - 1, 27270825161b5bf51ed48319e142751a9c88b104994Jeff Brown bottom, mTextLevelPaint); 27370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 27470825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Size: ").append(ps.mCoords.size, 2) 27570825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 6, base, mTextPaint); 27670825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 27770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 27870825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Pointer trace. 27970825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int p = 0; p < NP; p++) { 28070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(p); 28170825161b5bf51ed48319e142751a9c88b104994Jeff Brown 28270825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw path. 28370825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int N = ps.mTraceCount; 28470825161b5bf51ed48319e142751a9c88b104994Jeff Brown float lastX = 0, lastY = 0; 28570825161b5bf51ed48319e142751a9c88b104994Jeff Brown boolean haveLast = false; 28670825161b5bf51ed48319e142751a9c88b104994Jeff Brown boolean drawn = false; 28770825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, 128, 255, 255); 28870825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int i=0; i < N; i++) { 28970825161b5bf51ed48319e142751a9c88b104994Jeff Brown float x = ps.mTraceX[i]; 29070825161b5bf51ed48319e142751a9c88b104994Jeff Brown float y = ps.mTraceY[i]; 29170825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (Float.isNaN(x)) { 29270825161b5bf51ed48319e142751a9c88b104994Jeff Brown haveLast = false; 29370825161b5bf51ed48319e142751a9c88b104994Jeff Brown continue; 29490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 29570825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (haveLast) { 29670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(lastX, lastY, x, y, mPathPaint); 29770825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawPoint(lastX, lastY, mPaint); 29870825161b5bf51ed48319e142751a9c88b104994Jeff Brown drawn = true; 2998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 30070825161b5bf51ed48319e142751a9c88b104994Jeff Brown lastX = x; 30170825161b5bf51ed48319e142751a9c88b104994Jeff Brown lastY = y; 30270825161b5bf51ed48319e142751a9c88b104994Jeff Brown haveLast = true; 30370825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 30470825161b5bf51ed48319e142751a9c88b104994Jeff Brown 30570825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (drawn) { 30670825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw movement estimate curve. 30770825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(128, 128, 0, 128); 30870825161b5bf51ed48319e142751a9c88b104994Jeff Brown float lx = ps.mEstimator.estimateX(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 30970825161b5bf51ed48319e142751a9c88b104994Jeff Brown float ly = ps.mEstimator.estimateY(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 31070825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int i = -ESTIMATE_PAST_POINTS + 1; i <= ESTIMATE_FUTURE_POINTS; i++) { 31170825161b5bf51ed48319e142751a9c88b104994Jeff Brown float x = ps.mEstimator.estimateX(i * ESTIMATE_INTERVAL); 31270825161b5bf51ed48319e142751a9c88b104994Jeff Brown float y = ps.mEstimator.estimateY(i * ESTIMATE_INTERVAL); 31370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(lx, ly, x, y, mPaint); 31470825161b5bf51ed48319e142751a9c88b104994Jeff Brown lx = x; 31570825161b5bf51ed48319e142751a9c88b104994Jeff Brown ly = y; 31670825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 31770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 31870825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw velocity vector. 31970825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, 255, 64, 128); 32070825161b5bf51ed48319e142751a9c88b104994Jeff Brown float xVel = ps.mXVelocity * (1000 / 60); 32170825161b5bf51ed48319e142751a9c88b104994Jeff Brown float yVel = ps.mYVelocity * (1000 / 60); 32270825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); 3239eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 3249eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown // Draw alternate estimate. 3259eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 3269eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mPaint.setARGB(128, 0, 128, 128); 3279eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown lx = ps.mAltEstimator.estimateX(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 3289eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ly = ps.mAltEstimator.estimateY(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 3299eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown for (int i = -ESTIMATE_PAST_POINTS + 1; i <= ESTIMATE_FUTURE_POINTS; i++) { 3309eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown float x = ps.mAltEstimator.estimateX(i * ESTIMATE_INTERVAL); 3319eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown float y = ps.mAltEstimator.estimateY(i * ESTIMATE_INTERVAL); 3329eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown canvas.drawLine(lx, ly, x, y, mPaint); 3339eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown lx = x; 3349eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ly = y; 3359eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 3369eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 3379eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mPaint.setARGB(255, 64, 255, 128); 3389eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown xVel = ps.mAltXVelocity * (1000 / 60); 3399eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown yVel = ps.mAltYVelocity * (1000 / 60); 3409eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); 3419eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 34270825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 34370825161b5bf51ed48319e142751a9c88b104994Jeff Brown 34470825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mCurDown && ps.mCurDown) { 34570825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw crosshairs. 34670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint); 34770825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint); 34870825161b5bf51ed48319e142751a9c88b104994Jeff Brown 34970825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw current point. 35070825161b5bf51ed48319e142751a9c88b104994Jeff Brown int pressureLevel = (int)(ps.mCoords.pressure * 255); 35170825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel); 35270825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint); 35370825161b5bf51ed48319e142751a9c88b104994Jeff Brown 35470825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw current touch ellipse. 35570825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128); 35670825161b5bf51ed48319e142751a9c88b104994Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor, 35770825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint); 35870825161b5bf51ed48319e142751a9c88b104994Jeff Brown 35970825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw current tool ellipse. 36070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel); 36170825161b5bf51ed48319e142751a9c88b104994Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor, 36270825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint); 36370825161b5bf51ed48319e142751a9c88b104994Jeff Brown 36470825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw the orientation arrow. 36570825161b5bf51ed48319e142751a9c88b104994Jeff Brown float arrowSize = ps.mCoords.toolMajor * 0.7f; 36670825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (arrowSize < 20) { 36770825161b5bf51ed48319e142751a9c88b104994Jeff Brown arrowSize = 20; 36870825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 36970825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 255, 0); 37070825161b5bf51ed48319e142751a9c88b104994Jeff Brown float orientationVectorX = (float) (Math.sin(ps.mCoords.orientation) 37170825161b5bf51ed48319e142751a9c88b104994Jeff Brown * arrowSize); 37270825161b5bf51ed48319e142751a9c88b104994Jeff Brown float orientationVectorY = (float) (-Math.cos(ps.mCoords.orientation) 37370825161b5bf51ed48319e142751a9c88b104994Jeff Brown * arrowSize); 37470825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (ps.mToolType == MotionEvent.TOOL_TYPE_STYLUS 37570825161b5bf51ed48319e142751a9c88b104994Jeff Brown || ps.mToolType == MotionEvent.TOOL_TYPE_ERASER) { 37670825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Show full circle orientation. 37770825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(ps.mCoords.x, ps.mCoords.y, 37870825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x + orientationVectorX, 37970825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y + orientationVectorY, 38070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint); 38170825161b5bf51ed48319e142751a9c88b104994Jeff Brown } else { 38270825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Show half circle orientation. 38370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine( 38470825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x - orientationVectorX, 38570825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y - orientationVectorY, 38670825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x + orientationVectorX, 38770825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y + orientationVectorY, 38870825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint); 38990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 39070825161b5bf51ed48319e142751a9c88b104994Jeff Brown 39170825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw the tilt point along the orientation arrow. 39270825161b5bf51ed48319e142751a9c88b104994Jeff Brown float tiltScale = (float) Math.sin( 39370825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.getAxisValue(MotionEvent.AXIS_TILT)); 39470825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawCircle( 39570825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x + orientationVectorX * tiltScale, 39670825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y + orientationVectorY * tiltScale, 39770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 3.0f, mPaint); 39886172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright 39986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright // Draw the current bounding box 40086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright if (ps.mHasBoundingBox) { 40186172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright canvas.drawRect(ps.mBoundingLeft, ps.mBoundingTop, 40286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingRight, ps.mBoundingBottom, mPaint); 40386172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright } 40490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 40590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 40690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 40765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown 40865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private void logMotionEvent(String type, MotionEvent event) { 40965fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int action = event.getAction(); 41065fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int N = event.getHistorySize(); 41165fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int NI = event.getPointerCount(); 41265fd251c3913fc921468a3dad190810db19eb9dfJeff Brown for (int historyPos = 0; historyPos < N; historyPos++) { 41365fd251c3913fc921468a3dad190810db19eb9dfJeff Brown for (int i = 0; i < NI; i++) { 41465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int id = event.getPointerId(i); 41565fd251c3913fc921468a3dad190810db19eb9dfJeff Brown event.getHistoricalPointerCoords(i, historyPos, mTempCoords); 41686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords(type, action, i, mTempCoords, id, event); 41765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 41865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 41965fd251c3913fc921468a3dad190810db19eb9dfJeff Brown for (int i = 0; i < NI; i++) { 42065fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int id = event.getPointerId(i); 42165fd251c3913fc921468a3dad190810db19eb9dfJeff Brown event.getPointerCoords(i, mTempCoords); 42286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords(type, action, i, mTempCoords, id, event); 42365fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 42465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 42565fd251c3913fc921468a3dad190810db19eb9dfJeff Brown 42665fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private void logCoords(String type, int action, int index, 42786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright MotionEvent.PointerCoords coords, int id, MotionEvent event) { 42886172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright final int toolType = event.getToolType(index); 42986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright final int buttonState = event.getButtonState(); 43033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final String prefix; 43133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown switch (action & MotionEvent.ACTION_MASK) { 43233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_DOWN: 43333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "DOWN"; 43433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 43533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_UP: 43633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "UP"; 43733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 43833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_MOVE: 43933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 44033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 44133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_CANCEL: 44233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "CANCEL"; 44333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 44433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_OUTSIDE: 44533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "OUTSIDE"; 44633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 44733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_POINTER_DOWN: 44833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 44933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { 45033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "DOWN"; 45133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } else { 45233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 45333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 45433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 45533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_POINTER_UP: 45633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 45733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { 45833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "UP"; 45933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } else { 46033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 46133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 46233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 46333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_HOVER_MOVE: 46433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "HOVER MOVE"; 46533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 466a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown case MotionEvent.ACTION_HOVER_ENTER: 467a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown prefix = "HOVER ENTER"; 468a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown break; 469a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown case MotionEvent.ACTION_HOVER_EXIT: 470a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown prefix = "HOVER EXIT"; 471a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown break; 47233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_SCROLL: 47333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "SCROLL"; 47433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 47533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown default: 47633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = Integer.toString(action); 47733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 47833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 47933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 4808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, mText.clear() 48165fd251c3913fc921468a3dad190810db19eb9dfJeff Brown .append(type).append(" id ").append(id + 1) 48233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(": ") 48333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(prefix) 48433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(" (").append(coords.x, 3).append(", ").append(coords.y, 3) 4858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(") Pressure=").append(coords.pressure, 3) 4868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Size=").append(coords.size, 3) 4878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMajor=").append(coords.touchMajor, 3) 4888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMinor=").append(coords.touchMinor, 3) 4898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMajor=").append(coords.toolMajor, 3) 4908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMinor=").append(coords.toolMinor, 3) 4918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) 4926f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append("deg") 49365fd251c3913fc921468a3dad190810db19eb9dfJeff Brown .append(" Tilt=").append((float)( 49465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown coords.getAxisValue(MotionEvent.AXIS_TILT) * 180 / Math.PI), 1) 49565fd251c3913fc921468a3dad190810db19eb9dfJeff Brown .append("deg") 49680fd47ce75253dcdc2cfa85d7a3f42634b923a47Jeff Brown .append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1) 4976f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1) 4986f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1) 49986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(" BoundingBox=[(") 50086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(event.getAxisValue(MotionEvent.AXIS_GENERIC_1), 3) 50186172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(", ").append(event.getAxisValue(MotionEvent.AXIS_GENERIC_2), 3).append(")") 50286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(", (").append(event.getAxisValue(MotionEvent.AXIS_GENERIC_3), 3) 50386172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(", ").append(event.getAxisValue(MotionEvent.AXIS_GENERIC_4), 3) 50486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(")]") 505fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown .append(" ToolType=").append(MotionEvent.toolTypeToString(toolType)) 506fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown .append(" ButtonState=").append(MotionEvent.buttonStateToString(buttonState)) 5076f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .toString()); 5088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 50990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 51033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown public void addPointerEvent(MotionEvent event) { 51170825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int action = event.getAction(); 51270825161b5bf51ed48319e142751a9c88b104994Jeff Brown int NP = mPointers.size(); 51333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 51470825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (action == MotionEvent.ACTION_DOWN 51570825161b5bf51ed48319e142751a9c88b104994Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { 51670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 51770825161b5bf51ed48319e142751a9c88b104994Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down 51870825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (action == MotionEvent.ACTION_DOWN) { 51970825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int p=0; p<NP; p++) { 52070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(p); 52170825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.clearTrace(); 52270825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCurDown = false; 52333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 52470825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurDown = true; 52570825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers = 0; 52670825161b5bf51ed48319e142751a9c88b104994Jeff Brown mMaxNumPointers = 0; 52770825161b5bf51ed48319e142751a9c88b104994Jeff Brown mVelocity.clear(); 5289eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 5299eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.clear(); 5309eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 53170825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 53233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 53370825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers += 1; 53470825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mMaxNumPointers < mCurNumPointers) { 53570825161b5bf51ed48319e142751a9c88b104994Jeff Brown mMaxNumPointers = mCurNumPointers; 53690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 537cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown 53870825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int id = event.getPointerId(index); 53970825161b5bf51ed48319e142751a9c88b104994Jeff Brown while (NP <= id) { 54070825161b5bf51ed48319e142751a9c88b104994Jeff Brown PointerState ps = new PointerState(); 54170825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPointers.add(ps); 54270825161b5bf51ed48319e142751a9c88b104994Jeff Brown NP++; 54370825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 54470825161b5bf51ed48319e142751a9c88b104994Jeff Brown 54570825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mActivePointerId < 0 || 54670825161b5bf51ed48319e142751a9c88b104994Jeff Brown !mPointers.get(mActivePointerId).mCurDown) { 54770825161b5bf51ed48319e142751a9c88b104994Jeff Brown mActivePointerId = id; 54833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 54970825161b5bf51ed48319e142751a9c88b104994Jeff Brown 55070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(id); 55170825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCurDown = true; 5522f1cd7e68bc1f45243191f63984523ba6d36b590Michael Wright InputDevice device = InputDevice.getDevice(event.getDeviceId()); 5532f1cd7e68bc1f45243191f63984523ba6d36b590Michael Wright ps.mHasBoundingBox = device != null && 5542f1cd7e68bc1f45243191f63984523ba6d36b590Michael Wright device.getMotionRange(MotionEvent.AXIS_GENERIC_1) != null; 55570825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 55670825161b5bf51ed48319e142751a9c88b104994Jeff Brown 55770825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int NI = event.getPointerCount(); 55870825161b5bf51ed48319e142751a9c88b104994Jeff Brown 55970825161b5bf51ed48319e142751a9c88b104994Jeff Brown mVelocity.addMovement(event); 56070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mVelocity.computeCurrentVelocity(1); 5619eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 5629eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.addMovement(event); 5639eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.computeCurrentVelocity(1); 5649eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 56570825161b5bf51ed48319e142751a9c88b104994Jeff Brown 56670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int N = event.getHistorySize(); 56770825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int historyPos = 0; historyPos < N; historyPos++) { 56833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown for (int i = 0; i < NI; i++) { 56933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final int id = event.getPointerId(i); 57033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final PointerState ps = mCurDown ? mPointers.get(id) : null; 57165fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords; 57270825161b5bf51ed48319e142751a9c88b104994Jeff Brown event.getHistoricalPointerCoords(i, historyPos, coords); 57390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 57486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords("Pointer", action, i, coords, id, event); 575cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown } 576cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown if (ps != null) { 577cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown ps.addTrace(coords.x, coords.y); 57890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 57990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 58070825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 58170825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int i = 0; i < NI; i++) { 58270825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int id = event.getPointerId(i); 58370825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mCurDown ? mPointers.get(id) : null; 58470825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords; 58570825161b5bf51ed48319e142751a9c88b104994Jeff Brown event.getPointerCoords(i, coords); 58670825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mPrintCoords) { 58786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords("Pointer", action, i, coords, id, event); 58870825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 58970825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (ps != null) { 59070825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.addTrace(coords.x, coords.y); 59170825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mXVelocity = mVelocity.getXVelocity(id); 59270825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mYVelocity = mVelocity.getYVelocity(id); 59385bd0d62830a098c1bdc720dfdcf4fe1b18b657cJeff Brown mVelocity.getEstimator(id, ps.mEstimator); 5949eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 5959eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ps.mAltXVelocity = mAltVelocity.getXVelocity(id); 5969eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ps.mAltYVelocity = mAltVelocity.getYVelocity(id); 5979eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.getEstimator(id, ps.mAltEstimator); 5989eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 59970825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mToolType = event.getToolType(i); 60086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright 60186172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright if (ps.mHasBoundingBox) { 60286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingLeft = event.getAxisValue(MotionEvent.AXIS_GENERIC_1, i); 60386172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingTop = event.getAxisValue(MotionEvent.AXIS_GENERIC_2, i); 60486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingRight = event.getAxisValue(MotionEvent.AXIS_GENERIC_3, i); 60586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingBottom = event.getAxisValue(MotionEvent.AXIS_GENERIC_4, i); 60686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright } 60770825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 60870825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 60970825161b5bf51ed48319e142751a9c88b104994Jeff Brown 61070825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (action == MotionEvent.ACTION_UP 61170825161b5bf51ed48319e142751a9c88b104994Jeff Brown || action == MotionEvent.ACTION_CANCEL 61270825161b5bf51ed48319e142751a9c88b104994Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { 61370825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 61470825161b5bf51ed48319e142751a9c88b104994Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP 61570825161b5bf51ed48319e142751a9c88b104994Jeff Brown 61670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int id = event.getPointerId(index); 61770825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(id); 61870825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCurDown = false; 61933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 6208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_UP 62170825161b5bf51ed48319e142751a9c88b104994Jeff Brown || action == MotionEvent.ACTION_CANCEL) { 62270825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurDown = false; 62370825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers = 0; 62470825161b5bf51ed48319e142751a9c88b104994Jeff Brown } else { 62570825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers -= 1; 62670825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mActivePointerId == id) { 62770825161b5bf51ed48319e142751a9c88b104994Jeff Brown mActivePointerId = event.getPointerId(index == 0 ? 1 : 0); 62890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 62970825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.addTrace(Float.NaN, Float.NaN); 63090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 63190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 63270825161b5bf51ed48319e142751a9c88b104994Jeff Brown 63370825161b5bf51ed48319e142751a9c88b104994Jeff Brown invalidate(); 63490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 63590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 63690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 63790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public boolean onTouchEvent(MotionEvent event) { 63833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown addPointerEvent(event); 639c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 640c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) { 641c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown requestFocus(); 642c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 64390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn return true; 64490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 6457d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 6467d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn @Override 64733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown public boolean onGenericMotionEvent(MotionEvent event) { 648c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown final int source = event.getSource(); 649c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 65033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown addPointerEvent(event); 651c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 65265fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Joystick", event); 653c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) { 65465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Position", event); 655c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else { 65665fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Generic", event); 657c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 658c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 659c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 660c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 661c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown @Override 662c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown public boolean onKeyDown(int keyCode, KeyEvent event) { 663c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (shouldLogKey(keyCode)) { 664c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown final int repeatCount = event.getRepeatCount(); 665c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (repeatCount == 0) { 666c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Down: " + event); 667c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else { 668c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Repeat #" + repeatCount + ": " + event); 669c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 67033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown return true; 67133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 672c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return super.onKeyDown(keyCode, event); 673c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 674c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 675c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown @Override 676c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown public boolean onKeyUp(int keyCode, KeyEvent event) { 677c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (shouldLogKey(keyCode)) { 678c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Up: " + event); 679c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 680c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 681c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return super.onKeyUp(keyCode, event); 682c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 683c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 684c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown private static boolean shouldLogKey(int keyCode) { 685c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown switch (keyCode) { 686c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_UP: 687c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_DOWN: 688c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_LEFT: 689c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_RIGHT: 690c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_CENTER: 691c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 692c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown default: 693c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return KeyEvent.isGamepadButton(keyCode) 694c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown || KeyEvent.isModifierKey(keyCode); 695c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 69633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 69733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 69833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown @Override 6997d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn public boolean onTrackballEvent(MotionEvent event) { 70065fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Trackball", event); 701c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 7027d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn } 703af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 704af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 705af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown protected void onAttachedToWindow() { 706af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown super.onAttachedToWindow(); 707af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 708af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown mIm.registerInputDeviceListener(this, getHandler()); 709af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDevices(); 710af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 711af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 712af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 713af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown protected void onDetachedFromWindow() { 714af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown super.onDetachedFromWindow(); 715af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 716af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown mIm.unregisterInputDeviceListener(this); 717af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 718af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 719af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 720af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown public void onInputDeviceAdded(int deviceId) { 721af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceId, "Device Added"); 722af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 723af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 724af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 725af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown public void onInputDeviceChanged(int deviceId) { 726af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceId, "Device Changed"); 727af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 728af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 729af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 730af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown public void onInputDeviceRemoved(int deviceId) { 731af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceId, "Device Removed"); 732af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 733af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 734af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown private void logInputDevices() { 735af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown int[] deviceIds = InputDevice.getDeviceIds(); 736af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown for (int i = 0; i < deviceIds.length; i++) { 737af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceIds[i], "Device Enumerated"); 738af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 739af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 740af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 741af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown private void logInputDeviceState(int deviceId, String state) { 742af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown InputDevice device = mIm.getInputDevice(deviceId); 743af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown if (device != null) { 744af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown Log.i(TAG, state + ": " + device); 745af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } else { 746af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown Log.i(TAG, state + ": " + deviceId); 747af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 748af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 749af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 7508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // HACK 7518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // A quick and dirty string builder implementation optimized for GC. 752d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // Using String.format causes the application grind to a halt when 753d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // more than a couple of pointers are down due to the number of 754d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // temporary objects allocated while formatting strings for drawing or logging. 7558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final class FasterStringBuilder { 7568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private char[] mChars; 7578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mLength; 7588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder() { 7608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = new char[64]; 7618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder clear() { 7648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = 0; 7658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 7668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(String value) { 7698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int valueLength = value.length(); 7708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = reserve(valueLength); 7718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value.getChars(0, valueLength, mChars, index); 7728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += valueLength; 7738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 7748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value) { 7778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return append(value, 0); 7788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value, int zeroPadWidth) { 7818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final boolean negative = value < 0; 7828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 7838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = - value; 7848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value < 0) { 7858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("-2147483648"); 7868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 7878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int index = reserve(11); 7918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] chars = mChars; 7928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value == 0) { 7948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 7958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += 1; 7968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 7978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 8008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '-'; 8018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int divisor = 1000000000; 8048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int numberWidth = 10; 8058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown while (value < divisor) { 8068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 8078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown numberWidth -= 1; 8088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (numberWidth < zeroPadWidth) { 8098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 8108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown do { 8148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int digit = value / divisor; 8158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= digit * divisor; 8168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 8178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = (char) (digit + '0'); 8188d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } while (divisor != 0); 8198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = index; 8218d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 8228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(float value, int precision) { 8258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int scale = 1; 8268d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i = 0; i < precision; i++) { 8278d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown scale *= 10; 8288d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8298d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = (float) (Math.rint(value * scale) / scale); 8308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) value); 8328d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (precision != 0) { 8348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("."); 8358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = Math.abs(value); 8368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= Math.floor(value); 8378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) (value * scale), precision); 8388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 8418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown @Override 8448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public String toString() { 8458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return new String(mChars, 0, mLength); 8468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int reserve(int length) { 8498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldLength = mLength; 8508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newLength = mLength + length; 8518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] oldChars = mChars; 8528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldCapacity = oldChars.length; 8538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (newLength > oldCapacity) { 8548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newCapacity = oldCapacity * 2; 8558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] newChars = new char[newCapacity]; 8568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(oldChars, 0, newChars, 0, oldLength); 8578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = newChars; 8588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return oldLength; 8608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 86290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn} 863