1*90c8c64dSAndroid Build Coastguard Worker /* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2013 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Worker 17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.basicmultitouch; 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Worker import android.content.Context; 20*90c8c64dSAndroid Build Coastguard Worker import android.graphics.Canvas; 21*90c8c64dSAndroid Build Coastguard Worker import android.graphics.Color; 22*90c8c64dSAndroid Build Coastguard Worker import android.graphics.Paint; 23*90c8c64dSAndroid Build Coastguard Worker import android.graphics.PointF; 24*90c8c64dSAndroid Build Coastguard Worker import android.util.AttributeSet; 25*90c8c64dSAndroid Build Coastguard Worker import android.util.SparseArray; 26*90c8c64dSAndroid Build Coastguard Worker import android.view.MotionEvent; 27*90c8c64dSAndroid Build Coastguard Worker import android.view.View; 28*90c8c64dSAndroid Build Coastguard Worker 29*90c8c64dSAndroid Build Coastguard Worker import com.example.android.basicmultitouch.Pools.SimplePool; 30*90c8c64dSAndroid Build Coastguard Worker 31*90c8c64dSAndroid Build Coastguard Worker /** 32*90c8c64dSAndroid Build Coastguard Worker * View that shows touch events and their history. This view demonstrates the 33*90c8c64dSAndroid Build Coastguard Worker * use of {@link #onTouchEvent(android.view.MotionEvent)} and {@link android.view.MotionEvent}s to keep 34*90c8c64dSAndroid Build Coastguard Worker * track of touch pointers across events. 35*90c8c64dSAndroid Build Coastguard Worker */ 36*90c8c64dSAndroid Build Coastguard Worker public class TouchDisplayView extends View { 37*90c8c64dSAndroid Build Coastguard Worker 38*90c8c64dSAndroid Build Coastguard Worker // Hold data for active touch pointer IDs 39*90c8c64dSAndroid Build Coastguard Worker private SparseArray<TouchHistory> mTouches; 40*90c8c64dSAndroid Build Coastguard Worker 41*90c8c64dSAndroid Build Coastguard Worker // Is there an active touch? 42*90c8c64dSAndroid Build Coastguard Worker private boolean mHasTouch = false; 43*90c8c64dSAndroid Build Coastguard Worker 44*90c8c64dSAndroid Build Coastguard Worker /** 45*90c8c64dSAndroid Build Coastguard Worker * Holds data related to a touch pointer, including its current position, 46*90c8c64dSAndroid Build Coastguard Worker * pressure and historical positions. Objects are allocated through an 47*90c8c64dSAndroid Build Coastguard Worker * object pool using {@link #obtain()} and {@link #recycle()} to reuse 48*90c8c64dSAndroid Build Coastguard Worker * existing objects. 49*90c8c64dSAndroid Build Coastguard Worker */ 50*90c8c64dSAndroid Build Coastguard Worker static final class TouchHistory { 51*90c8c64dSAndroid Build Coastguard Worker 52*90c8c64dSAndroid Build Coastguard Worker // number of historical points to store 53*90c8c64dSAndroid Build Coastguard Worker public static final int HISTORY_COUNT = 20; 54*90c8c64dSAndroid Build Coastguard Worker 55*90c8c64dSAndroid Build Coastguard Worker public float x; 56*90c8c64dSAndroid Build Coastguard Worker public float y; 57*90c8c64dSAndroid Build Coastguard Worker public float pressure = 0f; 58*90c8c64dSAndroid Build Coastguard Worker public String label = null; 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard Worker // current position in history array 61*90c8c64dSAndroid Build Coastguard Worker public int historyIndex = 0; 62*90c8c64dSAndroid Build Coastguard Worker public int historyCount = 0; 63*90c8c64dSAndroid Build Coastguard Worker 64*90c8c64dSAndroid Build Coastguard Worker // arrray of pointer position history 65*90c8c64dSAndroid Build Coastguard Worker public PointF[] history = new PointF[HISTORY_COUNT]; 66*90c8c64dSAndroid Build Coastguard Worker 67*90c8c64dSAndroid Build Coastguard Worker private static final int MAX_POOL_SIZE = 10; 68*90c8c64dSAndroid Build Coastguard Worker private static final SimplePool<TouchHistory> sPool = 69*90c8c64dSAndroid Build Coastguard Worker new SimplePool<TouchHistory>(MAX_POOL_SIZE); 70*90c8c64dSAndroid Build Coastguard Worker obtain(float x, float y, float pressure)71*90c8c64dSAndroid Build Coastguard Worker public static TouchHistory obtain(float x, float y, float pressure) { 72*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = sPool.acquire(); 73*90c8c64dSAndroid Build Coastguard Worker if (data == null) { 74*90c8c64dSAndroid Build Coastguard Worker data = new TouchHistory(); 75*90c8c64dSAndroid Build Coastguard Worker } 76*90c8c64dSAndroid Build Coastguard Worker 77*90c8c64dSAndroid Build Coastguard Worker data.setTouch(x, y, pressure); 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Worker return data; 80*90c8c64dSAndroid Build Coastguard Worker } 81*90c8c64dSAndroid Build Coastguard Worker TouchHistory()82*90c8c64dSAndroid Build Coastguard Worker public TouchHistory() { 83*90c8c64dSAndroid Build Coastguard Worker 84*90c8c64dSAndroid Build Coastguard Worker // initialise history array 85*90c8c64dSAndroid Build Coastguard Worker for (int i = 0; i < HISTORY_COUNT; i++) { 86*90c8c64dSAndroid Build Coastguard Worker history[i] = new PointF(); 87*90c8c64dSAndroid Build Coastguard Worker } 88*90c8c64dSAndroid Build Coastguard Worker } 89*90c8c64dSAndroid Build Coastguard Worker setTouch(float x, float y, float pressure)90*90c8c64dSAndroid Build Coastguard Worker public void setTouch(float x, float y, float pressure) { 91*90c8c64dSAndroid Build Coastguard Worker this.x = x; 92*90c8c64dSAndroid Build Coastguard Worker this.y = y; 93*90c8c64dSAndroid Build Coastguard Worker this.pressure = pressure; 94*90c8c64dSAndroid Build Coastguard Worker } 95*90c8c64dSAndroid Build Coastguard Worker recycle()96*90c8c64dSAndroid Build Coastguard Worker public void recycle() { 97*90c8c64dSAndroid Build Coastguard Worker this.historyIndex = 0; 98*90c8c64dSAndroid Build Coastguard Worker this.historyCount = 0; 99*90c8c64dSAndroid Build Coastguard Worker sPool.release(this); 100*90c8c64dSAndroid Build Coastguard Worker } 101*90c8c64dSAndroid Build Coastguard Worker 102*90c8c64dSAndroid Build Coastguard Worker /** 103*90c8c64dSAndroid Build Coastguard Worker * Add a point to its history. Overwrites oldest point if the maximum 104*90c8c64dSAndroid Build Coastguard Worker * number of historical points is already stored. 105*90c8c64dSAndroid Build Coastguard Worker * 106*90c8c64dSAndroid Build Coastguard Worker * @param point 107*90c8c64dSAndroid Build Coastguard Worker */ addHistory(float x, float y)108*90c8c64dSAndroid Build Coastguard Worker public void addHistory(float x, float y) { 109*90c8c64dSAndroid Build Coastguard Worker PointF p = history[historyIndex]; 110*90c8c64dSAndroid Build Coastguard Worker p.x = x; 111*90c8c64dSAndroid Build Coastguard Worker p.y = y; 112*90c8c64dSAndroid Build Coastguard Worker 113*90c8c64dSAndroid Build Coastguard Worker historyIndex = (historyIndex + 1) % history.length; 114*90c8c64dSAndroid Build Coastguard Worker 115*90c8c64dSAndroid Build Coastguard Worker if (historyCount < HISTORY_COUNT) { 116*90c8c64dSAndroid Build Coastguard Worker historyCount++; 117*90c8c64dSAndroid Build Coastguard Worker } 118*90c8c64dSAndroid Build Coastguard Worker } 119*90c8c64dSAndroid Build Coastguard Worker 120*90c8c64dSAndroid Build Coastguard Worker } 121*90c8c64dSAndroid Build Coastguard Worker TouchDisplayView(Context context, AttributeSet attrs)122*90c8c64dSAndroid Build Coastguard Worker public TouchDisplayView(Context context, AttributeSet attrs) { 123*90c8c64dSAndroid Build Coastguard Worker super(context, attrs); 124*90c8c64dSAndroid Build Coastguard Worker 125*90c8c64dSAndroid Build Coastguard Worker // SparseArray for touch events, indexed by touch id 126*90c8c64dSAndroid Build Coastguard Worker mTouches = new SparseArray<TouchHistory>(10); 127*90c8c64dSAndroid Build Coastguard Worker 128*90c8c64dSAndroid Build Coastguard Worker initialisePaint(); 129*90c8c64dSAndroid Build Coastguard Worker } 130*90c8c64dSAndroid Build Coastguard Worker 131*90c8c64dSAndroid Build Coastguard Worker // BEGIN_INCLUDE(onTouchEvent) 132*90c8c64dSAndroid Build Coastguard Worker @Override onTouchEvent(MotionEvent event)133*90c8c64dSAndroid Build Coastguard Worker public boolean onTouchEvent(MotionEvent event) { 134*90c8c64dSAndroid Build Coastguard Worker 135*90c8c64dSAndroid Build Coastguard Worker final int action = event.getAction(); 136*90c8c64dSAndroid Build Coastguard Worker 137*90c8c64dSAndroid Build Coastguard Worker /* 138*90c8c64dSAndroid Build Coastguard Worker * Switch on the action. The action is extracted from the event by 139*90c8c64dSAndroid Build Coastguard Worker * applying the MotionEvent.ACTION_MASK. Alternatively a call to 140*90c8c64dSAndroid Build Coastguard Worker * event.getActionMasked() would yield in the action as well. 141*90c8c64dSAndroid Build Coastguard Worker */ 142*90c8c64dSAndroid Build Coastguard Worker switch (action & MotionEvent.ACTION_MASK) { 143*90c8c64dSAndroid Build Coastguard Worker 144*90c8c64dSAndroid Build Coastguard Worker case MotionEvent.ACTION_DOWN: { 145*90c8c64dSAndroid Build Coastguard Worker // first pressed gesture has started 146*90c8c64dSAndroid Build Coastguard Worker 147*90c8c64dSAndroid Build Coastguard Worker /* 148*90c8c64dSAndroid Build Coastguard Worker * Only one touch event is stored in the MotionEvent. Extract 149*90c8c64dSAndroid Build Coastguard Worker * the pointer identifier of this touch from the first index 150*90c8c64dSAndroid Build Coastguard Worker * within the MotionEvent object. 151*90c8c64dSAndroid Build Coastguard Worker */ 152*90c8c64dSAndroid Build Coastguard Worker int id = event.getPointerId(0); 153*90c8c64dSAndroid Build Coastguard Worker 154*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = TouchHistory.obtain(event.getX(0), event.getY(0), 155*90c8c64dSAndroid Build Coastguard Worker event.getPressure(0)); 156*90c8c64dSAndroid Build Coastguard Worker data.label = "id: " + 0; 157*90c8c64dSAndroid Build Coastguard Worker 158*90c8c64dSAndroid Build Coastguard Worker /* 159*90c8c64dSAndroid Build Coastguard Worker * Store the data under its pointer identifier. The pointer 160*90c8c64dSAndroid Build Coastguard Worker * number stays consistent for the duration of a gesture, 161*90c8c64dSAndroid Build Coastguard Worker * accounting for other pointers going up or down. 162*90c8c64dSAndroid Build Coastguard Worker */ 163*90c8c64dSAndroid Build Coastguard Worker mTouches.put(id, data); 164*90c8c64dSAndroid Build Coastguard Worker 165*90c8c64dSAndroid Build Coastguard Worker mHasTouch = true; 166*90c8c64dSAndroid Build Coastguard Worker 167*90c8c64dSAndroid Build Coastguard Worker break; 168*90c8c64dSAndroid Build Coastguard Worker } 169*90c8c64dSAndroid Build Coastguard Worker 170*90c8c64dSAndroid Build Coastguard Worker case MotionEvent.ACTION_POINTER_DOWN: { 171*90c8c64dSAndroid Build Coastguard Worker /* 172*90c8c64dSAndroid Build Coastguard Worker * A non-primary pointer has gone down, after an event for the 173*90c8c64dSAndroid Build Coastguard Worker * primary pointer (ACTION_DOWN) has already been received. 174*90c8c64dSAndroid Build Coastguard Worker */ 175*90c8c64dSAndroid Build Coastguard Worker 176*90c8c64dSAndroid Build Coastguard Worker /* 177*90c8c64dSAndroid Build Coastguard Worker * The MotionEvent object contains multiple pointers. Need to 178*90c8c64dSAndroid Build Coastguard Worker * extract the index at which the data for this particular event 179*90c8c64dSAndroid Build Coastguard Worker * is stored. 180*90c8c64dSAndroid Build Coastguard Worker */ 181*90c8c64dSAndroid Build Coastguard Worker int index = event.getActionIndex(); 182*90c8c64dSAndroid Build Coastguard Worker int id = event.getPointerId(index); 183*90c8c64dSAndroid Build Coastguard Worker 184*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = TouchHistory.obtain(event.getX(index), event.getY(index), 185*90c8c64dSAndroid Build Coastguard Worker event.getPressure(index)); 186*90c8c64dSAndroid Build Coastguard Worker data.label = "id: " + id; 187*90c8c64dSAndroid Build Coastguard Worker 188*90c8c64dSAndroid Build Coastguard Worker /* 189*90c8c64dSAndroid Build Coastguard Worker * Store the data under its pointer identifier. The index of 190*90c8c64dSAndroid Build Coastguard Worker * this pointer can change over multiple events, but this 191*90c8c64dSAndroid Build Coastguard Worker * pointer is always identified by the same identifier for this 192*90c8c64dSAndroid Build Coastguard Worker * active gesture. 193*90c8c64dSAndroid Build Coastguard Worker */ 194*90c8c64dSAndroid Build Coastguard Worker mTouches.put(id, data); 195*90c8c64dSAndroid Build Coastguard Worker 196*90c8c64dSAndroid Build Coastguard Worker break; 197*90c8c64dSAndroid Build Coastguard Worker } 198*90c8c64dSAndroid Build Coastguard Worker 199*90c8c64dSAndroid Build Coastguard Worker case MotionEvent.ACTION_UP: { 200*90c8c64dSAndroid Build Coastguard Worker /* 201*90c8c64dSAndroid Build Coastguard Worker * Final pointer has gone up and has ended the last pressed 202*90c8c64dSAndroid Build Coastguard Worker * gesture. 203*90c8c64dSAndroid Build Coastguard Worker */ 204*90c8c64dSAndroid Build Coastguard Worker 205*90c8c64dSAndroid Build Coastguard Worker /* 206*90c8c64dSAndroid Build Coastguard Worker * Extract the pointer identifier for the only event stored in 207*90c8c64dSAndroid Build Coastguard Worker * the MotionEvent object and remove it from the list of active 208*90c8c64dSAndroid Build Coastguard Worker * touches. 209*90c8c64dSAndroid Build Coastguard Worker */ 210*90c8c64dSAndroid Build Coastguard Worker int id = event.getPointerId(0); 211*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = mTouches.get(id); 212*90c8c64dSAndroid Build Coastguard Worker mTouches.remove(id); 213*90c8c64dSAndroid Build Coastguard Worker data.recycle(); 214*90c8c64dSAndroid Build Coastguard Worker 215*90c8c64dSAndroid Build Coastguard Worker mHasTouch = false; 216*90c8c64dSAndroid Build Coastguard Worker 217*90c8c64dSAndroid Build Coastguard Worker break; 218*90c8c64dSAndroid Build Coastguard Worker } 219*90c8c64dSAndroid Build Coastguard Worker 220*90c8c64dSAndroid Build Coastguard Worker case MotionEvent.ACTION_POINTER_UP: { 221*90c8c64dSAndroid Build Coastguard Worker /* 222*90c8c64dSAndroid Build Coastguard Worker * A non-primary pointer has gone up and other pointers are 223*90c8c64dSAndroid Build Coastguard Worker * still active. 224*90c8c64dSAndroid Build Coastguard Worker */ 225*90c8c64dSAndroid Build Coastguard Worker 226*90c8c64dSAndroid Build Coastguard Worker /* 227*90c8c64dSAndroid Build Coastguard Worker * The MotionEvent object contains multiple pointers. Need to 228*90c8c64dSAndroid Build Coastguard Worker * extract the index at which the data for this particular event 229*90c8c64dSAndroid Build Coastguard Worker * is stored. 230*90c8c64dSAndroid Build Coastguard Worker */ 231*90c8c64dSAndroid Build Coastguard Worker int index = event.getActionIndex(); 232*90c8c64dSAndroid Build Coastguard Worker int id = event.getPointerId(index); 233*90c8c64dSAndroid Build Coastguard Worker 234*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = mTouches.get(id); 235*90c8c64dSAndroid Build Coastguard Worker mTouches.remove(id); 236*90c8c64dSAndroid Build Coastguard Worker data.recycle(); 237*90c8c64dSAndroid Build Coastguard Worker 238*90c8c64dSAndroid Build Coastguard Worker break; 239*90c8c64dSAndroid Build Coastguard Worker } 240*90c8c64dSAndroid Build Coastguard Worker 241*90c8c64dSAndroid Build Coastguard Worker case MotionEvent.ACTION_MOVE: { 242*90c8c64dSAndroid Build Coastguard Worker /* 243*90c8c64dSAndroid Build Coastguard Worker * A change event happened during a pressed gesture. (Between 244*90c8c64dSAndroid Build Coastguard Worker * ACTION_DOWN and ACTION_UP or ACTION_POINTER_DOWN and 245*90c8c64dSAndroid Build Coastguard Worker * ACTION_POINTER_UP) 246*90c8c64dSAndroid Build Coastguard Worker */ 247*90c8c64dSAndroid Build Coastguard Worker 248*90c8c64dSAndroid Build Coastguard Worker /* 249*90c8c64dSAndroid Build Coastguard Worker * Loop through all active pointers contained within this event. 250*90c8c64dSAndroid Build Coastguard Worker * Data for each pointer is stored in a MotionEvent at an index 251*90c8c64dSAndroid Build Coastguard Worker * (starting from 0 up to the number of active pointers). This 252*90c8c64dSAndroid Build Coastguard Worker * loop goes through each of these active pointers, extracts its 253*90c8c64dSAndroid Build Coastguard Worker * data (position and pressure) and updates its stored data. A 254*90c8c64dSAndroid Build Coastguard Worker * pointer is identified by its pointer number which stays 255*90c8c64dSAndroid Build Coastguard Worker * constant across touch events as long as it remains active. 256*90c8c64dSAndroid Build Coastguard Worker * This identifier is used to keep track of a pointer across 257*90c8c64dSAndroid Build Coastguard Worker * events. 258*90c8c64dSAndroid Build Coastguard Worker */ 259*90c8c64dSAndroid Build Coastguard Worker for (int index = 0; index < event.getPointerCount(); index++) { 260*90c8c64dSAndroid Build Coastguard Worker // get pointer id for data stored at this index 261*90c8c64dSAndroid Build Coastguard Worker int id = event.getPointerId(index); 262*90c8c64dSAndroid Build Coastguard Worker 263*90c8c64dSAndroid Build Coastguard Worker // get the data stored externally about this pointer. 264*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = mTouches.get(id); 265*90c8c64dSAndroid Build Coastguard Worker 266*90c8c64dSAndroid Build Coastguard Worker // add previous position to history and add new values 267*90c8c64dSAndroid Build Coastguard Worker data.addHistory(data.x, data.y); 268*90c8c64dSAndroid Build Coastguard Worker data.setTouch(event.getX(index), event.getY(index), 269*90c8c64dSAndroid Build Coastguard Worker event.getPressure(index)); 270*90c8c64dSAndroid Build Coastguard Worker 271*90c8c64dSAndroid Build Coastguard Worker } 272*90c8c64dSAndroid Build Coastguard Worker 273*90c8c64dSAndroid Build Coastguard Worker break; 274*90c8c64dSAndroid Build Coastguard Worker } 275*90c8c64dSAndroid Build Coastguard Worker } 276*90c8c64dSAndroid Build Coastguard Worker 277*90c8c64dSAndroid Build Coastguard Worker // trigger redraw on UI thread 278*90c8c64dSAndroid Build Coastguard Worker this.postInvalidate(); 279*90c8c64dSAndroid Build Coastguard Worker 280*90c8c64dSAndroid Build Coastguard Worker return true; 281*90c8c64dSAndroid Build Coastguard Worker } 282*90c8c64dSAndroid Build Coastguard Worker 283*90c8c64dSAndroid Build Coastguard Worker // END_INCLUDE(onTouchEvent) 284*90c8c64dSAndroid Build Coastguard Worker 285*90c8c64dSAndroid Build Coastguard Worker @Override onDraw(Canvas canvas)286*90c8c64dSAndroid Build Coastguard Worker protected void onDraw(Canvas canvas) { 287*90c8c64dSAndroid Build Coastguard Worker super.onDraw(canvas); 288*90c8c64dSAndroid Build Coastguard Worker 289*90c8c64dSAndroid Build Coastguard Worker // Canvas background color depends on whether there is an active touch 290*90c8c64dSAndroid Build Coastguard Worker if (mHasTouch) { 291*90c8c64dSAndroid Build Coastguard Worker canvas.drawColor(BACKGROUND_ACTIVE); 292*90c8c64dSAndroid Build Coastguard Worker } else { 293*90c8c64dSAndroid Build Coastguard Worker // draw inactive border 294*90c8c64dSAndroid Build Coastguard Worker canvas.drawRect(mBorderWidth, mBorderWidth, getWidth() - mBorderWidth, getHeight() 295*90c8c64dSAndroid Build Coastguard Worker - mBorderWidth, mBorderPaint); 296*90c8c64dSAndroid Build Coastguard Worker } 297*90c8c64dSAndroid Build Coastguard Worker 298*90c8c64dSAndroid Build Coastguard Worker // loop through all active touches and draw them 299*90c8c64dSAndroid Build Coastguard Worker for (int i = 0; i < mTouches.size(); i++) { 300*90c8c64dSAndroid Build Coastguard Worker 301*90c8c64dSAndroid Build Coastguard Worker // get the pointer id and associated data for this index 302*90c8c64dSAndroid Build Coastguard Worker int id = mTouches.keyAt(i); 303*90c8c64dSAndroid Build Coastguard Worker TouchHistory data = mTouches.valueAt(i); 304*90c8c64dSAndroid Build Coastguard Worker 305*90c8c64dSAndroid Build Coastguard Worker // draw the data and its history to the canvas 306*90c8c64dSAndroid Build Coastguard Worker drawCircle(canvas, id, data); 307*90c8c64dSAndroid Build Coastguard Worker } 308*90c8c64dSAndroid Build Coastguard Worker } 309*90c8c64dSAndroid Build Coastguard Worker 310*90c8c64dSAndroid Build Coastguard Worker /* 311*90c8c64dSAndroid Build Coastguard Worker * Below are only helper methods and variables required for drawing. 312*90c8c64dSAndroid Build Coastguard Worker */ 313*90c8c64dSAndroid Build Coastguard Worker 314*90c8c64dSAndroid Build Coastguard Worker // radius of active touch circle in dp 315*90c8c64dSAndroid Build Coastguard Worker private static final float CIRCLE_RADIUS_DP = 75f; 316*90c8c64dSAndroid Build Coastguard Worker // radius of historical circle in dp 317*90c8c64dSAndroid Build Coastguard Worker private static final float CIRCLE_HISTORICAL_RADIUS_DP = 7f; 318*90c8c64dSAndroid Build Coastguard Worker 319*90c8c64dSAndroid Build Coastguard Worker // calculated radiuses in px 320*90c8c64dSAndroid Build Coastguard Worker private float mCircleRadius; 321*90c8c64dSAndroid Build Coastguard Worker private float mCircleHistoricalRadius; 322*90c8c64dSAndroid Build Coastguard Worker 323*90c8c64dSAndroid Build Coastguard Worker private Paint mCirclePaint = new Paint(); 324*90c8c64dSAndroid Build Coastguard Worker private Paint mTextPaint = new Paint(); 325*90c8c64dSAndroid Build Coastguard Worker 326*90c8c64dSAndroid Build Coastguard Worker private static final int BACKGROUND_ACTIVE = Color.WHITE; 327*90c8c64dSAndroid Build Coastguard Worker 328*90c8c64dSAndroid Build Coastguard Worker // inactive border 329*90c8c64dSAndroid Build Coastguard Worker private static final float INACTIVE_BORDER_DP = 15f; 330*90c8c64dSAndroid Build Coastguard Worker private static final int INACTIVE_BORDER_COLOR = 0xFFffd060; 331*90c8c64dSAndroid Build Coastguard Worker private Paint mBorderPaint = new Paint(); 332*90c8c64dSAndroid Build Coastguard Worker private float mBorderWidth; 333*90c8c64dSAndroid Build Coastguard Worker 334*90c8c64dSAndroid Build Coastguard Worker public final int[] COLORS = { 335*90c8c64dSAndroid Build Coastguard Worker 0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444, 336*90c8c64dSAndroid Build Coastguard Worker 0xFF0099CC, 0xFF9933CC, 0xFF669900, 0xFFFF8800, 0xFFCC0000 337*90c8c64dSAndroid Build Coastguard Worker }; 338*90c8c64dSAndroid Build Coastguard Worker 339*90c8c64dSAndroid Build Coastguard Worker /** 340*90c8c64dSAndroid Build Coastguard Worker * Sets up the required {@link android.graphics.Paint} objects for the screen density of this 341*90c8c64dSAndroid Build Coastguard Worker * device. 342*90c8c64dSAndroid Build Coastguard Worker */ initialisePaint()343*90c8c64dSAndroid Build Coastguard Worker private void initialisePaint() { 344*90c8c64dSAndroid Build Coastguard Worker 345*90c8c64dSAndroid Build Coastguard Worker // Calculate radiuses in px from dp based on screen density 346*90c8c64dSAndroid Build Coastguard Worker float density = getResources().getDisplayMetrics().density; 347*90c8c64dSAndroid Build Coastguard Worker mCircleRadius = CIRCLE_RADIUS_DP * density; 348*90c8c64dSAndroid Build Coastguard Worker mCircleHistoricalRadius = CIRCLE_HISTORICAL_RADIUS_DP * density; 349*90c8c64dSAndroid Build Coastguard Worker 350*90c8c64dSAndroid Build Coastguard Worker // Setup text paint for circle label 351*90c8c64dSAndroid Build Coastguard Worker mTextPaint.setTextSize(27f); 352*90c8c64dSAndroid Build Coastguard Worker mTextPaint.setColor(Color.BLACK); 353*90c8c64dSAndroid Build Coastguard Worker 354*90c8c64dSAndroid Build Coastguard Worker // Setup paint for inactive border 355*90c8c64dSAndroid Build Coastguard Worker mBorderWidth = INACTIVE_BORDER_DP * density; 356*90c8c64dSAndroid Build Coastguard Worker mBorderPaint.setStrokeWidth(mBorderWidth); 357*90c8c64dSAndroid Build Coastguard Worker mBorderPaint.setColor(INACTIVE_BORDER_COLOR); 358*90c8c64dSAndroid Build Coastguard Worker mBorderPaint.setStyle(Paint.Style.STROKE); 359*90c8c64dSAndroid Build Coastguard Worker 360*90c8c64dSAndroid Build Coastguard Worker } 361*90c8c64dSAndroid Build Coastguard Worker 362*90c8c64dSAndroid Build Coastguard Worker /** 363*90c8c64dSAndroid Build Coastguard Worker * Draws the data encapsulated by a {@link TouchDisplayView.TouchHistory} object to a canvas. 364*90c8c64dSAndroid Build Coastguard Worker * A large circle indicates the current position held by the 365*90c8c64dSAndroid Build Coastguard Worker * {@link TouchDisplayView.TouchHistory} object, while a smaller circle is drawn for each 366*90c8c64dSAndroid Build Coastguard Worker * entry in its history. The size of the large circle is scaled depending on 367*90c8c64dSAndroid Build Coastguard Worker * its pressure, clamped to a maximum of <code>1.0</code>. 368*90c8c64dSAndroid Build Coastguard Worker * 369*90c8c64dSAndroid Build Coastguard Worker * @param canvas 370*90c8c64dSAndroid Build Coastguard Worker * @param id 371*90c8c64dSAndroid Build Coastguard Worker * @param data 372*90c8c64dSAndroid Build Coastguard Worker */ drawCircle(Canvas canvas, int id, TouchHistory data)373*90c8c64dSAndroid Build Coastguard Worker protected void drawCircle(Canvas canvas, int id, TouchHistory data) { 374*90c8c64dSAndroid Build Coastguard Worker // select the color based on the id 375*90c8c64dSAndroid Build Coastguard Worker int color = COLORS[id % COLORS.length]; 376*90c8c64dSAndroid Build Coastguard Worker mCirclePaint.setColor(color); 377*90c8c64dSAndroid Build Coastguard Worker 378*90c8c64dSAndroid Build Coastguard Worker /* 379*90c8c64dSAndroid Build Coastguard Worker * Draw the circle, size scaled to its pressure. Pressure is clamped to 380*90c8c64dSAndroid Build Coastguard Worker * 1.0 max to ensure proper drawing. (Reported pressure values can 381*90c8c64dSAndroid Build Coastguard Worker * exceed 1.0, depending on the calibration of the touch screen). 382*90c8c64dSAndroid Build Coastguard Worker */ 383*90c8c64dSAndroid Build Coastguard Worker float pressure = Math.min(data.pressure, 1f); 384*90c8c64dSAndroid Build Coastguard Worker float radius = pressure * mCircleRadius; 385*90c8c64dSAndroid Build Coastguard Worker 386*90c8c64dSAndroid Build Coastguard Worker canvas.drawCircle(data.x, (data.y) - (radius / 2f), radius, 387*90c8c64dSAndroid Build Coastguard Worker mCirclePaint); 388*90c8c64dSAndroid Build Coastguard Worker 389*90c8c64dSAndroid Build Coastguard Worker // draw all historical points with a lower alpha value 390*90c8c64dSAndroid Build Coastguard Worker mCirclePaint.setAlpha(125); 391*90c8c64dSAndroid Build Coastguard Worker for (int j = 0; j < data.history.length && j < data.historyCount; j++) { 392*90c8c64dSAndroid Build Coastguard Worker PointF p = data.history[j]; 393*90c8c64dSAndroid Build Coastguard Worker canvas.drawCircle(p.x, p.y, mCircleHistoricalRadius, mCirclePaint); 394*90c8c64dSAndroid Build Coastguard Worker } 395*90c8c64dSAndroid Build Coastguard Worker 396*90c8c64dSAndroid Build Coastguard Worker // draw its label next to the main circle 397*90c8c64dSAndroid Build Coastguard Worker canvas.drawText(data.label, data.x + radius, data.y 398*90c8c64dSAndroid Build Coastguard Worker - radius, mTextPaint); 399*90c8c64dSAndroid Build Coastguard Worker } 400*90c8c64dSAndroid Build Coastguard Worker 401*90c8c64dSAndroid Build Coastguard Worker } 402