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