GestureTrailsDrawingPreview.java revision e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7
1470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka/* 2470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * Copyright (C) 2013 The Android Open Source Project 3470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * 4470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * you may not use this file except in compliance with the License. 6470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * You may obtain a copy of the License at 7470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * 8470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * 10470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 11470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * See the License for the specific language governing permissions and 14470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * limitations under the License. 15470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka */ 16470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 17470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokapackage com.android.inputmethod.keyboard.internal; 18470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 19470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.content.res.TypedArray; 20470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.Bitmap; 21470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.Canvas; 22470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.Color; 23470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.Paint; 24470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.PorterDuff; 25470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.PorterDuffXfermode; 26470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.graphics.Rect; 27470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.os.Message; 28470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.util.SparseArray; 29470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport android.view.View; 30470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 31470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker; 32e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils; 332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; 34470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 35470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka/** 36e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka * Draw preview graphics of multiple gesture trails during gesture input. 37470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka */ 38cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokapublic final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { 39e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka private final SparseArray<GestureTrailDrawingPoints> mGestureTrails = 40e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka CollectionUtils.newSparseArray(); 41e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka private final GestureTrailDrawingParams mDrawingParams; 42470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private final Paint mGesturePaint; 43470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private int mOffscreenWidth; 44470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private int mOffscreenHeight; 45470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private int mOffscreenOffsetY; 46470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private Bitmap mOffscreenBuffer; 47470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private final Canvas mOffscreenCanvas = new Canvas(); 48470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private final Rect mOffscreenSrcRect = new Rect(); 49470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private final Rect mDirtyRect = new Rect(); 50cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa private final Rect mGestureTrailBoundsRect = new Rect(); // per trail 51470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 52470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private final DrawingHandler mDrawingHandler; 53470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 54470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private static final class DrawingHandler 55cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka extends LeakGuardHandlerWrapper<GestureTrailsDrawingPreview> { 56cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa private static final int MSG_UPDATE_GESTURE_TRAIL = 0; 57470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 58e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka private final GestureTrailDrawingParams mDrawingParams; 59470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 60cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka public DrawingHandler(final GestureTrailsDrawingPreview ownerInstance, 61e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka final GestureTrailDrawingParams drawingParams) { 622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa super(ownerInstance); 63e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka mDrawingParams = drawingParams; 64470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 65470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 66470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka @Override 67470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka public void handleMessage(final Message msg) { 68cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka final GestureTrailsDrawingPreview preview = getOwnerInstance(); 692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (preview == null) { 702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 72470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka switch (msg.what) { 73cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa case MSG_UPDATE_GESTURE_TRAIL: 74470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka preview.getDrawingView().invalidate(); 75470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka break; 76470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 77470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 78470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 79470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka public void postUpdateGestureTrailPreview() { 80cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa removeMessages(MSG_UPDATE_GESTURE_TRAIL); 81cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_TRAIL), 82e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka mDrawingParams.mUpdateInterval); 83470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 84470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 85470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 86cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka public GestureTrailsDrawingPreview(final View drawingView, 87cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka final TypedArray mainKeyboardViewAttr) { 88470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka super(drawingView); 89e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka mDrawingParams = new GestureTrailDrawingParams(mainKeyboardViewAttr); 90e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka mDrawingHandler = new DrawingHandler(this, mDrawingParams); 91470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka final Paint gesturePaint = new Paint(); 92470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka gesturePaint.setAntiAlias(true); 93470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); 94470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mGesturePaint = gesturePaint; 95470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 96470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 97470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka @Override 98470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka public void setKeyboardGeometry(final int[] originCoords, final int width, final int height) { 99e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka mOffscreenOffsetY = (int)(height 100e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka * GestureStrokeRecognitionPoints.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); 101470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenWidth = width; 102470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenHeight = mOffscreenOffsetY + height; 103470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 104470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 105470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka @Override 106afca1ddd233c03d79433931a0b6ba97ed22663edTadashi G. Takaoka public void onDeallocateMemory() { 107c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa freeOffscreenBuffer(); 108c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa } 109c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa 110470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private void freeOffscreenBuffer() { 111c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa mOffscreenCanvas.setBitmap(null); 11282018f99727a104aa77ab4d48f8b9a9858479453Ken Wakasa mOffscreenCanvas.setMatrix(null); 113470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (mOffscreenBuffer != null) { 114470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenBuffer.recycle(); 115470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenBuffer = null; 116470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 117470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 118470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 119470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private void mayAllocateOffscreenBuffer() { 120470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (mOffscreenBuffer != null && mOffscreenBuffer.getWidth() == mOffscreenWidth 121470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka && mOffscreenBuffer.getHeight() == mOffscreenHeight) { 122470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka return; 123470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 124470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka freeOffscreenBuffer(); 125470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenBuffer = Bitmap.createBitmap( 126470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenWidth, mOffscreenHeight, Bitmap.Config.ARGB_8888); 127470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenCanvas.setBitmap(mOffscreenBuffer); 128470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenCanvas.translate(0, mOffscreenOffsetY); 129470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 130470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 131470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka private boolean drawGestureTrails(final Canvas offscreenCanvas, final Paint paint, 132470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka final Rect dirtyRect) { 133470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // Clear previous dirty rectangle. 134470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (!dirtyRect.isEmpty()) { 135470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka paint.setColor(Color.TRANSPARENT); 136470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka paint.setStyle(Paint.Style.FILL); 137470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka offscreenCanvas.drawRect(dirtyRect, paint); 138470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 139470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka dirtyRect.setEmpty(); 140cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa boolean needsUpdatingGestureTrail = false; 141470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // Draw gesture trails to offscreen buffer. 142cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa synchronized (mGestureTrails) { 143470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // Trails count == fingers count that have ever been active. 144cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa final int trailsCount = mGestureTrails.size(); 145470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka for (int index = 0; index < trailsCount; index++) { 146e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka final GestureTrailDrawingPoints trail = mGestureTrails.valueAt(index); 147cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa needsUpdatingGestureTrail |= trail.drawGestureTrail(offscreenCanvas, paint, 148e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka mGestureTrailBoundsRect, mDrawingParams); 149cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa // {@link #mGestureTrailBoundsRect} has bounding box of the trail. 150cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa dirtyRect.union(mGestureTrailBoundsRect); 151470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 152470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 153cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa return needsUpdatingGestureTrail; 154470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 155470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 156470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka /** 157470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * Draws the preview 158470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * @param canvas The canvas where the preview is drawn. 159470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka */ 160470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka @Override 161470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka public void drawPreview(final Canvas canvas) { 162470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (!isPreviewEnabled()) { 163470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka return; 164470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 165470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mayAllocateOffscreenBuffer(); 166470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // Draw gesture trails to offscreen buffer. 167cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa final boolean needsUpdatingGestureTrail = drawGestureTrails( 168470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenCanvas, mGesturePaint, mDirtyRect); 169cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa if (needsUpdatingGestureTrail) { 170470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mDrawingHandler.postUpdateGestureTrailPreview(); 171470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 172470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // Transfer offscreen buffer to screen. 173470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (!mDirtyRect.isEmpty()) { 174470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenSrcRect.set(mDirtyRect); 175470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka mOffscreenSrcRect.offset(0, mOffscreenOffsetY); 176470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka canvas.drawBitmap(mOffscreenBuffer, mOffscreenSrcRect, mDirtyRect, null); 177470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // Note: Defer clearing the dirty rectangle here because we will get cleared 178470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // rectangle on the canvas. 179470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 180470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 181470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 182470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka /** 183470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * Set the position of the preview. 184470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka * @param tracker The new location of the preview is based on the points in PointerTracker. 185470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka */ 186470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka @Override 187470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka public void setPreviewPosition(final PointerTracker tracker) { 188470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (!isPreviewEnabled()) { 189470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka return; 190470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 191e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka GestureTrailDrawingPoints trail; 192cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa synchronized (mGestureTrails) { 193cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa trail = mGestureTrails.get(tracker.mPointerId); 194470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka if (trail == null) { 195e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka trail = new GestureTrailDrawingPoints(); 196cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa mGestureTrails.put(tracker.mPointerId, trail); 197470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 198470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 199e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka trail.addStroke(tracker.getGestureStrokeDrawingPoints(), tracker.getDownTime()); 200470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka 201470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka // TODO: Should narrow the invalidate region. 202470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka getDrawingView().invalidate(); 203470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka } 204470a5805e125c32f1ed300bb0c064babb651923cTadashi G. Takaoka} 205