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]; 4976936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright private boolean[] mTraceCurrent = new boolean[32]; 508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mTraceCount; 518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // True if the pointer is down. 5390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent coordinates. 56cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown private PointerCoords mCoords = new PointerCoords(); 5765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private int mToolType; 588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Most recent velocity. 609e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mXVelocity; 619e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private float mYVelocity; 629eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private float mAltXVelocity; 639eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private float mAltYVelocity; 64b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown 6586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright // Current bounding box, if any 6686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private boolean mHasBoundingBox; 6786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingLeft; 6886172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingTop; 6986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingRight; 7086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright private float mBoundingBottom; 7186172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright 72b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown // Position estimator. 73b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private VelocityTracker.Estimator mEstimator = new VelocityTracker.Estimator(); 749eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private VelocityTracker.Estimator mAltEstimator = new VelocityTracker.Estimator(); 75b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown 768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public void clearTrace() { 778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount = 0; 788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8076936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright public void addTrace(float x, float y, boolean current) { 818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int traceCapacity = mTraceX.length; 828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (mTraceCount == traceCapacity) { 838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown traceCapacity *= 2; 848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceX = new float[traceCapacity]; 858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount); 868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX = newTraceX; 878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float[] newTraceY = new float[traceCapacity]; 898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount); 908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY = newTraceY; 9176936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright 9276936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright boolean[] newTraceCurrent = new boolean[traceCapacity]; 9376936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount); 9476936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mTraceCurrent= newTraceCurrent; 958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceX[mTraceCount] = x; 988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceY[mTraceCount] = y; 9976936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mTraceCurrent[mTraceCount] = current; 1008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mTraceCount += 1; 1018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 10290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 10390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 104b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private final int ESTIMATE_PAST_POINTS = 4; 105b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private final int ESTIMATE_FUTURE_POINTS = 2; 106b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown private final float ESTIMATE_INTERVAL = 0.02f; 107b59ab9f41faafb358afb4f951de96f34a656e0b4Jeff Brown 108af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown private final InputManager mIm; 109af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 11090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final ViewConfiguration mVC; 11190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextPaint; 11290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextBackgroundPaint; 11390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTextLevelPaint; 11490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPaint; 11576936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright private final Paint mCurrentPointPaint; 11690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mTargetPaint; 11790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final Paint mPathPaint; 11890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private final FontMetricsInt mTextMetrics = new FontMetricsInt(); 11990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mHeaderBottom; 12090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mCurDown; 12190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mCurNumPointers; 12290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private int mMaxNumPointers; 123d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown private int mActivePointerId; 1248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); 12565fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private final PointerCoords mTempCoords = new PointerCoords(); 12690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 1279e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown private final VelocityTracker mVelocity; 1289eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown private final VelocityTracker mAltVelocity; 1299eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 1308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private final FasterStringBuilder mText = new FasterStringBuilder(); 1318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 13290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn private boolean mPrintCoords = true; 13390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 13490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public PointerLocationView(Context c) { 13590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super(c); 136c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown setFocusableInTouchMode(true); 137c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 138af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown mIm = (InputManager)c.getSystemService(Context.INPUT_SERVICE); 139af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 14090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mVC = ViewConfiguration.get(c); 14190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint = new Paint(); 14290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setAntiAlias(true); 14390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setTextSize(10 14490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn * getResources().getDisplayMetrics().density); 14590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.setARGB(255, 0, 0, 0); 14690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint = new Paint(); 14790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setAntiAlias(false); 14890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextBackgroundPaint.setARGB(128, 255, 255, 255); 14990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint = new Paint(); 15090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setAntiAlias(false); 15190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextLevelPaint.setARGB(192, 255, 0, 0); 15290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint = new Paint(); 15390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setAntiAlias(true); 15490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setARGB(255, 255, 255, 255); 15590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 15690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(2); 15776936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mCurrentPointPaint = new Paint(); 15876936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mCurrentPointPaint.setAntiAlias(true); 15976936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mCurrentPointPaint.setARGB(255, 255, 0, 0); 16076936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mCurrentPointPaint.setStyle(Paint.Style.STROKE); 16176936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright mCurrentPointPaint.setStrokeWidth(2); 16290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint = new Paint(); 16390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setAntiAlias(false); 16490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTargetPaint.setARGB(255, 0, 0, 192); 16590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint = new Paint(); 16690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setAntiAlias(false); 16790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPathPaint.setARGB(255, 0, 96, 255); 16890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStyle(Paint.Style.STROKE); 16990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPaint.setStrokeWidth(1); 17090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 17190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn PointerState ps = new PointerState(); 17290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPointers.add(ps); 173d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown mActivePointerId = 0; 1749e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown 1759e2ad36be87f2703b3d737189944d82f93bd4f27Jeff Brown mVelocity = VelocityTracker.obtain(); 1769eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 1779eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown String altStrategy = SystemProperties.get(ALT_STRATEGY_PROPERY_KEY); 1789eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (altStrategy.length() != 0) { 1799eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown Log.d(TAG, "Comparing default velocity tracker strategy with " + altStrategy); 1809eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity = VelocityTracker.obtain(altStrategy); 1819eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } else { 1829eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity = null; 1839eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 18490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 18590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 18690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public void setPrintCoords(boolean state) { 18790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mPrintCoords = state; 18890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 18990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 19090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 19190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 19290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn super.onMeasure(widthMeasureSpec, heightMeasureSpec); 19390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mTextPaint.getFontMetricsInt(mTextMetrics); 19490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; 19590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (false) { 19690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent 19790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " descent=" + mTextMetrics.descent 19890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " leading=" + mTextMetrics.leading 19990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " top=" + mTextMetrics.top 20090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn + " bottom=" + mTextMetrics.bottom); 20190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 20290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 2038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 2048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // Draw an oval. When angle is 0 radians, orients the major axis vertically, 2058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // angles less than or greater than 0 radians rotate the major axis left or right. 2068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private RectF mReusableOvalRect = new RectF(); 2078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private void drawOval(Canvas canvas, float x, float y, float major, float minor, 2088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown float angle, Paint paint) { 2098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.save(Canvas.MATRIX_SAVE_FLAG); 2105068ad8d2396d6d7bfbdb1c2c3fe57104744f1f9Jeff Brown canvas.rotate((float) (angle * 180 / Math.PI), x, y); 2118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.left = x - minor / 2; 2128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.right = x + minor / 2; 2138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.top = y - major / 2; 2148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mReusableOvalRect.bottom = y + major / 2; 2158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawOval(mReusableOvalRect, paint); 2168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.restore(); 2178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 21890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 21990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 22090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn protected void onDraw(Canvas canvas) { 22170825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int w = getWidth(); 22270825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int itemW = w/7; 22370825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int base = -mTextMetrics.ascent+1; 22470825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int bottom = mHeaderBottom; 22570825161b5bf51ed48319e142751a9c88b104994Jeff Brown 22670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int NP = mPointers.size(); 22770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 22870825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Labels 22970825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mActivePointerId >= 0) { 23070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(mActivePointerId); 23190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 23270825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); 23370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 23470825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("P: ").append(mCurNumPointers) 23570825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append(" / ").append(mMaxNumPointers) 23670825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1, base, mTextPaint); 23770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 23870825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int N = ps.mTraceCount; 23970825161b5bf51ed48319e142751a9c88b104994Jeff Brown if ((mCurDown && ps.mCurDown) || N == 0) { 24070825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); 2418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 24270825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("X: ").append(ps.mCoords.x, 1) 24370825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 24470825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); 2458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 24670825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Y: ").append(ps.mCoords.y, 1) 24770825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 24870825161b5bf51ed48319e142751a9c88b104994Jeff Brown } else { 24970825161b5bf51ed48319e142751a9c88b104994Jeff Brown float dx = ps.mTraceX[N - 1] - ps.mTraceX[0]; 25070825161b5bf51ed48319e142751a9c88b104994Jeff Brown float dy = ps.mTraceY[N - 1] - ps.mTraceY[0]; 25170825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, 25270825161b5bf51ed48319e142751a9c88b104994Jeff Brown Math.abs(dx) < mVC.getScaledTouchSlop() 25370825161b5bf51ed48319e142751a9c88b104994Jeff Brown ? mTextBackgroundPaint : mTextLevelPaint); 2548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 25570825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("dX: ").append(dx, 1) 25670825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW, base, mTextPaint); 25770825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, 25870825161b5bf51ed48319e142751a9c88b104994Jeff Brown Math.abs(dy) < mVC.getScaledTouchSlop() 25970825161b5bf51ed48319e142751a9c88b104994Jeff Brown ? mTextBackgroundPaint : mTextLevelPaint); 2608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown canvas.drawText(mText.clear() 26170825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("dY: ").append(dy, 1) 26270825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 2, base, mTextPaint); 26390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 26470825161b5bf51ed48319e142751a9c88b104994Jeff Brown 26570825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); 26670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 26770825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Xv: ").append(ps.mXVelocity, 3) 26870825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 3, base, mTextPaint); 26970825161b5bf51ed48319e142751a9c88b104994Jeff Brown 27070825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); 27170825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 27270825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Yv: ").append(ps.mYVelocity, 3) 27370825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 4, base, mTextPaint); 27470825161b5bf51ed48319e142751a9c88b104994Jeff Brown 27570825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); 27670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, 27770825161b5bf51ed48319e142751a9c88b104994Jeff Brown bottom, mTextLevelPaint); 27870825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 27970825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Prs: ").append(ps.mCoords.pressure, 2) 28070825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 5, base, mTextPaint); 28170825161b5bf51ed48319e142751a9c88b104994Jeff Brown 28270825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); 28370825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCoords.size * itemW) - 1, 28470825161b5bf51ed48319e142751a9c88b104994Jeff Brown bottom, mTextLevelPaint); 28570825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawText(mText.clear() 28670825161b5bf51ed48319e142751a9c88b104994Jeff Brown .append("Size: ").append(ps.mCoords.size, 2) 28770825161b5bf51ed48319e142751a9c88b104994Jeff Brown .toString(), 1 + itemW * 6, base, mTextPaint); 28870825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 28970825161b5bf51ed48319e142751a9c88b104994Jeff Brown 29070825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Pointer trace. 29170825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int p = 0; p < NP; p++) { 29270825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(p); 29370825161b5bf51ed48319e142751a9c88b104994Jeff Brown 29470825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw path. 29570825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int N = ps.mTraceCount; 29670825161b5bf51ed48319e142751a9c88b104994Jeff Brown float lastX = 0, lastY = 0; 29770825161b5bf51ed48319e142751a9c88b104994Jeff Brown boolean haveLast = false; 29870825161b5bf51ed48319e142751a9c88b104994Jeff Brown boolean drawn = false; 29970825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, 128, 255, 255); 30070825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int i=0; i < N; i++) { 30170825161b5bf51ed48319e142751a9c88b104994Jeff Brown float x = ps.mTraceX[i]; 30270825161b5bf51ed48319e142751a9c88b104994Jeff Brown float y = ps.mTraceY[i]; 30370825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (Float.isNaN(x)) { 30470825161b5bf51ed48319e142751a9c88b104994Jeff Brown haveLast = false; 30570825161b5bf51ed48319e142751a9c88b104994Jeff Brown continue; 30690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 30770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (haveLast) { 30870825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(lastX, lastY, x, y, mPathPaint); 30976936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright final Paint paint = ps.mTraceCurrent[i] ? mCurrentPointPaint : mPaint; 31076936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright canvas.drawPoint(lastX, lastY, paint); 31170825161b5bf51ed48319e142751a9c88b104994Jeff Brown drawn = true; 3128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 31370825161b5bf51ed48319e142751a9c88b104994Jeff Brown lastX = x; 31470825161b5bf51ed48319e142751a9c88b104994Jeff Brown lastY = y; 31570825161b5bf51ed48319e142751a9c88b104994Jeff Brown haveLast = true; 31670825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 31770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 31870825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (drawn) { 31970825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw movement estimate curve. 32070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(128, 128, 0, 128); 32170825161b5bf51ed48319e142751a9c88b104994Jeff Brown float lx = ps.mEstimator.estimateX(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 32270825161b5bf51ed48319e142751a9c88b104994Jeff Brown float ly = ps.mEstimator.estimateY(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 32370825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int i = -ESTIMATE_PAST_POINTS + 1; i <= ESTIMATE_FUTURE_POINTS; i++) { 32470825161b5bf51ed48319e142751a9c88b104994Jeff Brown float x = ps.mEstimator.estimateX(i * ESTIMATE_INTERVAL); 32570825161b5bf51ed48319e142751a9c88b104994Jeff Brown float y = ps.mEstimator.estimateY(i * ESTIMATE_INTERVAL); 32670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(lx, ly, x, y, mPaint); 32770825161b5bf51ed48319e142751a9c88b104994Jeff Brown lx = x; 32870825161b5bf51ed48319e142751a9c88b104994Jeff Brown ly = y; 32970825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 33070825161b5bf51ed48319e142751a9c88b104994Jeff Brown 33170825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw velocity vector. 33270825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, 255, 64, 128); 33370825161b5bf51ed48319e142751a9c88b104994Jeff Brown float xVel = ps.mXVelocity * (1000 / 60); 33470825161b5bf51ed48319e142751a9c88b104994Jeff Brown float yVel = ps.mYVelocity * (1000 / 60); 33570825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); 3369eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 3379eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown // Draw alternate estimate. 3389eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 3399eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mPaint.setARGB(128, 0, 128, 128); 3409eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown lx = ps.mAltEstimator.estimateX(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 3419eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ly = ps.mAltEstimator.estimateY(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL); 3429eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown for (int i = -ESTIMATE_PAST_POINTS + 1; i <= ESTIMATE_FUTURE_POINTS; i++) { 3439eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown float x = ps.mAltEstimator.estimateX(i * ESTIMATE_INTERVAL); 3449eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown float y = ps.mAltEstimator.estimateY(i * ESTIMATE_INTERVAL); 3459eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown canvas.drawLine(lx, ly, x, y, mPaint); 3469eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown lx = x; 3479eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ly = y; 3489eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 3499eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown 3509eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mPaint.setARGB(255, 64, 255, 128); 3519eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown xVel = ps.mAltXVelocity * (1000 / 60); 3529eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown yVel = ps.mAltYVelocity * (1000 / 60); 3539eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); 3549eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 35570825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 35670825161b5bf51ed48319e142751a9c88b104994Jeff Brown 35770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mCurDown && ps.mCurDown) { 35870825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw crosshairs. 35970825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint); 36070825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint); 36170825161b5bf51ed48319e142751a9c88b104994Jeff Brown 36270825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw current point. 36370825161b5bf51ed48319e142751a9c88b104994Jeff Brown int pressureLevel = (int)(ps.mCoords.pressure * 255); 36470825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel); 36570825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint); 36670825161b5bf51ed48319e142751a9c88b104994Jeff Brown 36770825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw current touch ellipse. 36870825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128); 36970825161b5bf51ed48319e142751a9c88b104994Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor, 37070825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint); 37170825161b5bf51ed48319e142751a9c88b104994Jeff Brown 37270825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw current tool ellipse. 37370825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel); 37470825161b5bf51ed48319e142751a9c88b104994Jeff Brown drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor, 37570825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint); 37670825161b5bf51ed48319e142751a9c88b104994Jeff Brown 37770825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw the orientation arrow. 37870825161b5bf51ed48319e142751a9c88b104994Jeff Brown float arrowSize = ps.mCoords.toolMajor * 0.7f; 37970825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (arrowSize < 20) { 38070825161b5bf51ed48319e142751a9c88b104994Jeff Brown arrowSize = 20; 38170825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 38270825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint.setARGB(255, pressureLevel, 255, 0); 38370825161b5bf51ed48319e142751a9c88b104994Jeff Brown float orientationVectorX = (float) (Math.sin(ps.mCoords.orientation) 38470825161b5bf51ed48319e142751a9c88b104994Jeff Brown * arrowSize); 38570825161b5bf51ed48319e142751a9c88b104994Jeff Brown float orientationVectorY = (float) (-Math.cos(ps.mCoords.orientation) 38670825161b5bf51ed48319e142751a9c88b104994Jeff Brown * arrowSize); 38770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (ps.mToolType == MotionEvent.TOOL_TYPE_STYLUS 38870825161b5bf51ed48319e142751a9c88b104994Jeff Brown || ps.mToolType == MotionEvent.TOOL_TYPE_ERASER) { 38970825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Show full circle orientation. 39070825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine(ps.mCoords.x, ps.mCoords.y, 39170825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x + orientationVectorX, 39270825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y + orientationVectorY, 39370825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint); 39470825161b5bf51ed48319e142751a9c88b104994Jeff Brown } else { 39570825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Show half circle orientation. 39670825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawLine( 39770825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x - orientationVectorX, 39870825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y - orientationVectorY, 39970825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x + orientationVectorX, 40070825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y + orientationVectorY, 40170825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPaint); 40290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 40370825161b5bf51ed48319e142751a9c88b104994Jeff Brown 40470825161b5bf51ed48319e142751a9c88b104994Jeff Brown // Draw the tilt point along the orientation arrow. 40570825161b5bf51ed48319e142751a9c88b104994Jeff Brown float tiltScale = (float) Math.sin( 40670825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.getAxisValue(MotionEvent.AXIS_TILT)); 40770825161b5bf51ed48319e142751a9c88b104994Jeff Brown canvas.drawCircle( 40870825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.x + orientationVectorX * tiltScale, 40970825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCoords.y + orientationVectorY * tiltScale, 41070825161b5bf51ed48319e142751a9c88b104994Jeff Brown 3.0f, mPaint); 41186172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright 41286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright // Draw the current bounding box 41386172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright if (ps.mHasBoundingBox) { 41486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright canvas.drawRect(ps.mBoundingLeft, ps.mBoundingTop, 41586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingRight, ps.mBoundingBottom, mPaint); 41686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright } 41790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 41890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 41990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 42065fd251c3913fc921468a3dad190810db19eb9dfJeff Brown 42165fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private void logMotionEvent(String type, MotionEvent event) { 42265fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int action = event.getAction(); 42365fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int N = event.getHistorySize(); 42465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int NI = event.getPointerCount(); 42565fd251c3913fc921468a3dad190810db19eb9dfJeff Brown for (int historyPos = 0; historyPos < N; historyPos++) { 42665fd251c3913fc921468a3dad190810db19eb9dfJeff Brown for (int i = 0; i < NI; i++) { 42765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int id = event.getPointerId(i); 42865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown event.getHistoricalPointerCoords(i, historyPos, mTempCoords); 42986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords(type, action, i, mTempCoords, id, event); 43065fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 43165fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 43265fd251c3913fc921468a3dad190810db19eb9dfJeff Brown for (int i = 0; i < NI; i++) { 43365fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final int id = event.getPointerId(i); 43465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown event.getPointerCoords(i, mTempCoords); 43586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords(type, action, i, mTempCoords, id, event); 43665fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 43765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 43865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown 43965fd251c3913fc921468a3dad190810db19eb9dfJeff Brown private void logCoords(String type, int action, int index, 44086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright MotionEvent.PointerCoords coords, int id, MotionEvent event) { 44186172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright final int toolType = event.getToolType(index); 44286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright final int buttonState = event.getButtonState(); 44333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final String prefix; 44433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown switch (action & MotionEvent.ACTION_MASK) { 44533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_DOWN: 44633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "DOWN"; 44733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 44833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_UP: 44933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "UP"; 45033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 45133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_MOVE: 45233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 45333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 45433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_CANCEL: 45533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "CANCEL"; 45633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 45733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_OUTSIDE: 45833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "OUTSIDE"; 45933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 46033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_POINTER_DOWN: 46133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 46233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { 46333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "DOWN"; 46433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } else { 46533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 46633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 46733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 46833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_POINTER_UP: 46933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK) 47033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) { 47133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "UP"; 47233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } else { 47333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "MOVE"; 47433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 47533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 47633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_HOVER_MOVE: 47733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "HOVER MOVE"; 47833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 479a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown case MotionEvent.ACTION_HOVER_ENTER: 480a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown prefix = "HOVER ENTER"; 481a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown break; 482a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown case MotionEvent.ACTION_HOVER_EXIT: 483a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown prefix = "HOVER EXIT"; 484a032cc008618b83ecbbede537517d1e7998e3264Jeff Brown break; 48533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown case MotionEvent.ACTION_SCROLL: 48633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = "SCROLL"; 48733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 48833bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown default: 48933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown prefix = Integer.toString(action); 49033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown break; 49133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 49233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 4938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown Log.i(TAG, mText.clear() 49465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown .append(type).append(" id ").append(id + 1) 49533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(": ") 49633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(prefix) 49733bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown .append(" (").append(coords.x, 3).append(", ").append(coords.y, 3) 4988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(") Pressure=").append(coords.pressure, 3) 4998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Size=").append(coords.size, 3) 5008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMajor=").append(coords.touchMajor, 3) 5018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" TouchMinor=").append(coords.touchMinor, 3) 5028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMajor=").append(coords.toolMajor, 3) 5038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" ToolMinor=").append(coords.toolMinor, 3) 5048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) 5056f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append("deg") 50665fd251c3913fc921468a3dad190810db19eb9dfJeff Brown .append(" Tilt=").append((float)( 50765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown coords.getAxisValue(MotionEvent.AXIS_TILT) * 180 / Math.PI), 1) 50865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown .append("deg") 50980fd47ce75253dcdc2cfa85d7a3f42634b923a47Jeff Brown .append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1) 5106f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1) 5116f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1) 51286172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(" BoundingBox=[(") 51386172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(event.getAxisValue(MotionEvent.AXIS_GENERIC_1), 3) 51486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(", ").append(event.getAxisValue(MotionEvent.AXIS_GENERIC_2), 3).append(")") 51586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(", (").append(event.getAxisValue(MotionEvent.AXIS_GENERIC_3), 3) 51686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(", ").append(event.getAxisValue(MotionEvent.AXIS_GENERIC_4), 3) 51786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright .append(")]") 518fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown .append(" ToolType=").append(MotionEvent.toolTypeToString(toolType)) 519fe9f8ab03a63b1037f07dd85799fbea80ec6adaaJeff Brown .append(" ButtonState=").append(MotionEvent.buttonStateToString(buttonState)) 5206f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown .toString()); 5218d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 52290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 52333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown public void addPointerEvent(MotionEvent event) { 52470825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int action = event.getAction(); 52570825161b5bf51ed48319e142751a9c88b104994Jeff Brown int NP = mPointers.size(); 52633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 52770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (action == MotionEvent.ACTION_DOWN 52870825161b5bf51ed48319e142751a9c88b104994Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { 52970825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 53070825161b5bf51ed48319e142751a9c88b104994Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down 53170825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (action == MotionEvent.ACTION_DOWN) { 53270825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int p=0; p<NP; p++) { 53370825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(p); 53470825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.clearTrace(); 53570825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCurDown = false; 53633bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 53770825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurDown = true; 53870825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers = 0; 53970825161b5bf51ed48319e142751a9c88b104994Jeff Brown mMaxNumPointers = 0; 54070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mVelocity.clear(); 5419eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 5429eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.clear(); 5439eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 54470825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 54533bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 54670825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers += 1; 54770825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mMaxNumPointers < mCurNumPointers) { 54870825161b5bf51ed48319e142751a9c88b104994Jeff Brown mMaxNumPointers = mCurNumPointers; 54990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 550cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown 55170825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int id = event.getPointerId(index); 55270825161b5bf51ed48319e142751a9c88b104994Jeff Brown while (NP <= id) { 55370825161b5bf51ed48319e142751a9c88b104994Jeff Brown PointerState ps = new PointerState(); 55470825161b5bf51ed48319e142751a9c88b104994Jeff Brown mPointers.add(ps); 55570825161b5bf51ed48319e142751a9c88b104994Jeff Brown NP++; 55670825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 55770825161b5bf51ed48319e142751a9c88b104994Jeff Brown 55870825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mActivePointerId < 0 || 55970825161b5bf51ed48319e142751a9c88b104994Jeff Brown !mPointers.get(mActivePointerId).mCurDown) { 56070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mActivePointerId = id; 56133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 56270825161b5bf51ed48319e142751a9c88b104994Jeff Brown 56370825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(id); 56470825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCurDown = true; 5652f1cd7e68bc1f45243191f63984523ba6d36b590Michael Wright InputDevice device = InputDevice.getDevice(event.getDeviceId()); 5662f1cd7e68bc1f45243191f63984523ba6d36b590Michael Wright ps.mHasBoundingBox = device != null && 5672f1cd7e68bc1f45243191f63984523ba6d36b590Michael Wright device.getMotionRange(MotionEvent.AXIS_GENERIC_1) != null; 56870825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 56970825161b5bf51ed48319e142751a9c88b104994Jeff Brown 57070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int NI = event.getPointerCount(); 57170825161b5bf51ed48319e142751a9c88b104994Jeff Brown 57270825161b5bf51ed48319e142751a9c88b104994Jeff Brown mVelocity.addMovement(event); 57370825161b5bf51ed48319e142751a9c88b104994Jeff Brown mVelocity.computeCurrentVelocity(1); 5749eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 5759eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.addMovement(event); 5769eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.computeCurrentVelocity(1); 5779eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 57870825161b5bf51ed48319e142751a9c88b104994Jeff Brown 57970825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int N = event.getHistorySize(); 58070825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int historyPos = 0; historyPos < N; historyPos++) { 58133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown for (int i = 0; i < NI; i++) { 58233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final int id = event.getPointerId(i); 58333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown final PointerState ps = mCurDown ? mPointers.get(id) : null; 58465fd251c3913fc921468a3dad190810db19eb9dfJeff Brown final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords; 58570825161b5bf51ed48319e142751a9c88b104994Jeff Brown event.getHistoricalPointerCoords(i, historyPos, coords); 58690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn if (mPrintCoords) { 58786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords("Pointer", action, i, coords, id, event); 588cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown } 589cc0c159e9b3dd4e0f48da0ce3e33d2c68a651413Jeff Brown if (ps != null) { 59076936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright ps.addTrace(coords.x, coords.y, false); 59190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 59290d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 59370825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 59470825161b5bf51ed48319e142751a9c88b104994Jeff Brown for (int i = 0; i < NI; i++) { 59570825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int id = event.getPointerId(i); 59670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mCurDown ? mPointers.get(id) : null; 59770825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords; 59870825161b5bf51ed48319e142751a9c88b104994Jeff Brown event.getPointerCoords(i, coords); 59970825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mPrintCoords) { 60086172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright logCoords("Pointer", action, i, coords, id, event); 60170825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 60270825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (ps != null) { 60376936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright ps.addTrace(coords.x, coords.y, true); 60470825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mXVelocity = mVelocity.getXVelocity(id); 60570825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mYVelocity = mVelocity.getYVelocity(id); 60685bd0d62830a098c1bdc720dfdcf4fe1b18b657cJeff Brown mVelocity.getEstimator(id, ps.mEstimator); 6079eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown if (mAltVelocity != null) { 6089eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ps.mAltXVelocity = mAltVelocity.getXVelocity(id); 6099eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown ps.mAltYVelocity = mAltVelocity.getYVelocity(id); 6109eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown mAltVelocity.getEstimator(id, ps.mAltEstimator); 6119eb7d86181729c3eb769d71123c4ce9ffc868f08Jeff Brown } 61270825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mToolType = event.getToolType(i); 61386172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright 61486172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright if (ps.mHasBoundingBox) { 61586172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingLeft = event.getAxisValue(MotionEvent.AXIS_GENERIC_1, i); 61686172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingTop = event.getAxisValue(MotionEvent.AXIS_GENERIC_2, i); 61786172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingRight = event.getAxisValue(MotionEvent.AXIS_GENERIC_3, i); 61886172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright ps.mBoundingBottom = event.getAxisValue(MotionEvent.AXIS_GENERIC_4, i); 61986172f6252fe2ed49a1cdea5cafd0ba2e049255dMichael Wright } 62070825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 62170825161b5bf51ed48319e142751a9c88b104994Jeff Brown } 62270825161b5bf51ed48319e142751a9c88b104994Jeff Brown 62370825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (action == MotionEvent.ACTION_UP 62470825161b5bf51ed48319e142751a9c88b104994Jeff Brown || action == MotionEvent.ACTION_CANCEL 62570825161b5bf51ed48319e142751a9c88b104994Jeff Brown || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { 62670825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 62770825161b5bf51ed48319e142751a9c88b104994Jeff Brown >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP 62870825161b5bf51ed48319e142751a9c88b104994Jeff Brown 62970825161b5bf51ed48319e142751a9c88b104994Jeff Brown final int id = event.getPointerId(index); 63070825161b5bf51ed48319e142751a9c88b104994Jeff Brown final PointerState ps = mPointers.get(id); 63170825161b5bf51ed48319e142751a9c88b104994Jeff Brown ps.mCurDown = false; 63233bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 6338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (action == MotionEvent.ACTION_UP 63470825161b5bf51ed48319e142751a9c88b104994Jeff Brown || action == MotionEvent.ACTION_CANCEL) { 63570825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurDown = false; 63670825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers = 0; 63770825161b5bf51ed48319e142751a9c88b104994Jeff Brown } else { 63870825161b5bf51ed48319e142751a9c88b104994Jeff Brown mCurNumPointers -= 1; 63970825161b5bf51ed48319e142751a9c88b104994Jeff Brown if (mActivePointerId == id) { 64070825161b5bf51ed48319e142751a9c88b104994Jeff Brown mActivePointerId = event.getPointerId(index == 0 ? 1 : 0); 64190d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 64276936eb96acdaf7feb221000be3e0d154fa5000cMichael Wright ps.addTrace(Float.NaN, Float.NaN, false); 64390d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 64490d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 64570825161b5bf51ed48319e142751a9c88b104994Jeff Brown 64670825161b5bf51ed48319e142751a9c88b104994Jeff Brown invalidate(); 64790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 64890d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn 64990d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn @Override 65090d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn public boolean onTouchEvent(MotionEvent event) { 65133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown addPointerEvent(event); 652c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 653c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) { 654c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown requestFocus(); 655c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 65690d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn return true; 65790d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn } 6587d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn 6597d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn @Override 66033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown public boolean onGenericMotionEvent(MotionEvent event) { 661c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown final int source = event.getSource(); 662c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 66333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown addPointerEvent(event); 664c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 66565fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Joystick", event); 666c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) { 66765fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Position", event); 668c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else { 66965fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Generic", event); 670c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 671c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 672c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 673c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 674c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown @Override 675c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown public boolean onKeyDown(int keyCode, KeyEvent event) { 676c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (shouldLogKey(keyCode)) { 677c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown final int repeatCount = event.getRepeatCount(); 678c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (repeatCount == 0) { 679c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Down: " + event); 680c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } else { 681c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Repeat #" + repeatCount + ": " + event); 682c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 68333bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown return true; 68433bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 685c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return super.onKeyDown(keyCode, event); 686c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 687c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 688c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown @Override 689c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown public boolean onKeyUp(int keyCode, KeyEvent event) { 690c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown if (shouldLogKey(keyCode)) { 691c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown Log.i(TAG, "Key Up: " + event); 692c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 693c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 694c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return super.onKeyUp(keyCode, event); 695c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 696c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown 697c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown private static boolean shouldLogKey(int keyCode) { 698c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown switch (keyCode) { 699c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_UP: 700c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_DOWN: 701c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_LEFT: 702c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_RIGHT: 703c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown case KeyEvent.KEYCODE_DPAD_CENTER: 704c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 705c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown default: 706c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return KeyEvent.isGamepadButton(keyCode) 707c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown || KeyEvent.isModifierKey(keyCode); 708c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown } 70933bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown } 71033bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown 71133bbfd2232ea9eaae9a9d87a05a95a430f09bd83Jeff Brown @Override 7127d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn public boolean onTrackballEvent(MotionEvent event) { 71365fd251c3913fc921468a3dad190810db19eb9dfJeff Brown logMotionEvent("Trackball", event); 714c3fe7669d6276b43e82c802743a7e8974bae52a5Jeff Brown return true; 7157d9af5ae762c59e879a86e77dcb330856774bc09Dianne Hackborn } 716af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 717af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 718af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown protected void onAttachedToWindow() { 719af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown super.onAttachedToWindow(); 720af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 721af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown mIm.registerInputDeviceListener(this, getHandler()); 722af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDevices(); 723af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 724af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 725af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 726af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown protected void onDetachedFromWindow() { 727af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown super.onDetachedFromWindow(); 728af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 729af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown mIm.unregisterInputDeviceListener(this); 730af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 731af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 732af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 733af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown public void onInputDeviceAdded(int deviceId) { 734af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceId, "Device Added"); 735af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 736af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 737af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 738af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown public void onInputDeviceChanged(int deviceId) { 739af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceId, "Device Changed"); 740af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 741af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 742af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown @Override 743af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown public void onInputDeviceRemoved(int deviceId) { 744af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceId, "Device Removed"); 745af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 746af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 747af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown private void logInputDevices() { 748af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown int[] deviceIds = InputDevice.getDeviceIds(); 749af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown for (int i = 0; i < deviceIds.length; i++) { 750af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown logInputDeviceState(deviceIds[i], "Device Enumerated"); 751af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 752af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 753af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 754af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown private void logInputDeviceState(int deviceId, String state) { 755af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown InputDevice device = mIm.getInputDevice(deviceId); 756af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown if (device != null) { 757af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown Log.i(TAG, state + ": " + device); 758af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } else { 759af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown Log.i(TAG, state + ": " + deviceId); 760af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 761af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown } 762af9e8d38184c6ba4d2d3eb5bde7014a66dd8a78bJeff Brown 7638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // HACK 7648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown // A quick and dirty string builder implementation optimized for GC. 765d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // Using String.format causes the application grind to a halt when 766d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // more than a couple of pointers are down due to the number of 767d1e0c371a651f024b3de62a686c56e369e3f361eJeff Brown // temporary objects allocated while formatting strings for drawing or logging. 7688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private static final class FasterStringBuilder { 7698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private char[] mChars; 7708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int mLength; 7718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder() { 7738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = new char[64]; 7748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7758d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7768d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder clear() { 7778d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = 0; 7788d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 7798d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7808d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7818d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(String value) { 7828d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int valueLength = value.length(); 7838d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int index = reserve(valueLength); 7848d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value.getChars(0, valueLength, mChars, index); 7858d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += valueLength; 7868d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 7878d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7888d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7898d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value) { 7908d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return append(value, 0); 7918d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 7928d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 7938d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(int value, int zeroPadWidth) { 7948d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final boolean negative = value < 0; 7958d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 7968d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = - value; 7978d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value < 0) { 7988d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("-2147483648"); 7998d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 8008d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8018d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8028d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8038d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int index = reserve(11); 8048d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] chars = mChars; 8058d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8068d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (value == 0) { 8078d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 8088d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength += 1; 8098d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 8108d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8118d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8128d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (negative) { 8138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '-'; 8148d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8158d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8168d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int divisor = 1000000000; 8178d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int numberWidth = 10; 8188d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown while (value < divisor) { 8198d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 8208d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown numberWidth -= 1; 8218d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (numberWidth < zeroPadWidth) { 8228d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = '0'; 8238d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8248d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8258d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8268d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown do { 8278d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int digit = value / divisor; 8288d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= digit * divisor; 8298d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown divisor /= 10; 8308d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown chars[index++] = (char) (digit + '0'); 8318d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } while (divisor != 0); 8328d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8338d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mLength = index; 8348d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 8358d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8368d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8378d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public FasterStringBuilder append(float value, int precision) { 8388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown int scale = 1; 8398d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown for (int i = 0; i < precision; i++) { 8408d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown scale *= 10; 8418d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8428d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = (float) (Math.rint(value * scale) / scale); 8438d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8448d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) value); 8458d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8468d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (precision != 0) { 8478d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append("."); 8488d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value = Math.abs(value); 8498d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown value -= Math.floor(value); 8508d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown append((int) (value * scale), precision); 8518d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8528d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8538d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return this; 8548d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8558d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8568d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown @Override 8578d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown public String toString() { 8588d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return new String(mChars, 0, mLength); 8598d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8608d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown 8618d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown private int reserve(int length) { 8628d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldLength = mLength; 8638d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newLength = mLength + length; 8648d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] oldChars = mChars; 8658d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int oldCapacity = oldChars.length; 8668d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown if (newLength > oldCapacity) { 8678d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final int newCapacity = oldCapacity * 2; 8688d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown final char[] newChars = new char[newCapacity]; 8698d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown System.arraycopy(oldChars, 0, newChars, 0, oldLength); 8708d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown mChars = newChars; 8718d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8728d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown return oldLength; 8738d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 8748d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 87590d2db3d21d07c2a4b4cbbc558f5ec59d20098c3Dianne Hackborn} 876