Gesture.java revision 9ffe1ae56bf495b1ada1e9c1da523db0677d98b7
16e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato/*
26e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * Copyright (C) 2008-2009 The Android Open Source Project
36e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato *
46e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * Licensed under the Apache License, Version 2.0 (the "License");
56e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * you may not use this file except in compliance with the License.
66e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * You may obtain a copy of the License at
76e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato *
86e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato *      http://www.apache.org/licenses/LICENSE-2.0
96e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato *
106e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * Unless required by applicable law or agreed to in writing, software
116e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * distributed under the License is distributed on an "AS IS" BASIS,
126e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * See the License for the specific language governing permissions and
146e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * limitations under the License.
156e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato */
166e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
17db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guypackage android.gesture;
186e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
196e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.graphics.Bitmap;
206e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.graphics.Canvas;
216e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.graphics.Paint;
226e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.graphics.Path;
236e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.graphics.RectF;
246e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.os.Parcel;
256e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport android.os.Parcelable;
26b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guyimport android.util.Log;
276e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
286e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport java.io.IOException;
29b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guyimport java.io.DataOutputStream;
30b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guyimport java.io.DataInputStream;
31b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guyimport java.io.ByteArrayOutputStream;
32b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guyimport java.io.ByteArrayInputStream;
336e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratoimport java.util.ArrayList;
346e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
356e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato/**
3635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * A gesture can have a single or multiple strokes
376e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato */
386e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
396e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratopublic class Gesture implements Parcelable {
4035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static final long GESTURE_ID_BASE = System.currentTimeMillis();
4135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
4235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static final int BITMAP_RENDERING_WIDTH = 2;
4335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
4435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static final boolean BITMAP_RENDERING_ANTIALIAS = true;
4535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static final boolean BITMAP_RENDERING_DITHER = true;
4635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
4735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static int sGestureCount = 0;
4835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
499ffe1ae56bf495b1ada1e9c1da523db0677d98b7Romain Guy    private final RectF mBoundingBox = new RectF();
5035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
5135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the same as its instance ID
5235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private long mGestureID;
5335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
54c534727972c3835ed997e84a349f259915ef2cddRomain Guy    private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>();
556e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
566e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    public Gesture() {
5735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        mGestureID = GESTURE_ID_BASE + sGestureCount++;
586e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
596e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
6082f3495b146b267f3786997752cef25310176349Romain Guy    void recycle() {
6182f3495b146b267f3786997752cef25310176349Romain Guy        mStrokes.clear();
6282f3495b146b267f3786997752cef25310176349Romain Guy        mBoundingBox.setEmpty();
6382f3495b146b267f3786997752cef25310176349Romain Guy    }
6482f3495b146b267f3786997752cef25310176349Romain Guy
6535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
6635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return all the strokes of the gesture
6735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
6835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public ArrayList<GestureStroke> getStrokes() {
6935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return mStrokes;
70935fd37d27804539b141fa074c060d2c15524424Yang Li    }
7135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
7235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
7335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the number of strokes included by this gesture
7435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
7535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public int getStrokesCount() {
7635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return mStrokes.size();
776e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
786e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
7935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
8035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * Add a stroke to the gesture
8135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
8235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param stroke
8335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
8435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public void addStroke(GestureStroke stroke) {
8535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        mStrokes.add(stroke);
869ffe1ae56bf495b1ada1e9c1da523db0677d98b7Romain Guy        mBoundingBox.union(stroke.boundingBox);
876e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
886e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato
896e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    /**
9035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * Get the total length of the gesture. When there are multiple strokes in
9135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * the gesture, this returns the sum of the lengths of all the strokes
9235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
936e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     * @return the length of the gesture
946e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     */
956e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    public float getLength() {
9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        int len = 0;
97c534727972c3835ed997e84a349f259915ef2cddRomain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
98c534727972c3835ed997e84a349f259915ef2cddRomain Guy        final int count = strokes.size();
99c534727972c3835ed997e84a349f259915ef2cddRomain Guy
10035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < count; i++) {
101c534727972c3835ed997e84a349f259915ef2cddRomain Guy            len += strokes.get(i).length;
10235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
103c534727972c3835ed997e84a349f259915ef2cddRomain Guy
10435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return len;
1056e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
10635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
10735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
10835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the bounding box of the gesture
10935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
11035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public RectF getBoundingBox() {
11135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return mBoundingBox;
1126e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
11335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
11482f3495b146b267f3786997752cef25310176349Romain Guy    public Path toPath() {
11582f3495b146b267f3786997752cef25310176349Romain Guy        return toPath(null);
11682f3495b146b267f3786997752cef25310176349Romain Guy    }
11782f3495b146b267f3786997752cef25310176349Romain Guy
11882f3495b146b267f3786997752cef25310176349Romain Guy    public Path toPath(Path path) {
11982f3495b146b267f3786997752cef25310176349Romain Guy        if (path == null) path = new Path();
12082f3495b146b267f3786997752cef25310176349Romain Guy
12182f3495b146b267f3786997752cef25310176349Romain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
12282f3495b146b267f3786997752cef25310176349Romain Guy        final int count = strokes.size();
12382f3495b146b267f3786997752cef25310176349Romain Guy
12482f3495b146b267f3786997752cef25310176349Romain Guy        for (int i = 0; i < count; i++) {
12582f3495b146b267f3786997752cef25310176349Romain Guy            path.addPath(strokes.get(i).getPath());
12682f3495b146b267f3786997752cef25310176349Romain Guy        }
12782f3495b146b267f3786997752cef25310176349Romain Guy
12882f3495b146b267f3786997752cef25310176349Romain Guy        return path;
12982f3495b146b267f3786997752cef25310176349Romain Guy    }
13082f3495b146b267f3786997752cef25310176349Romain Guy
13182f3495b146b267f3786997752cef25310176349Romain Guy    public Path toPath(int width, int height, int edge, int numSample) {
13282f3495b146b267f3786997752cef25310176349Romain Guy        return toPath(null, width, height, edge, numSample);
13382f3495b146b267f3786997752cef25310176349Romain Guy    }
13482f3495b146b267f3786997752cef25310176349Romain Guy
13582f3495b146b267f3786997752cef25310176349Romain Guy    public Path toPath(Path path, int width, int height, int edge, int numSample) {
13682f3495b146b267f3786997752cef25310176349Romain Guy        if (path == null) path = new Path();
13782f3495b146b267f3786997752cef25310176349Romain Guy
13882f3495b146b267f3786997752cef25310176349Romain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
13982f3495b146b267f3786997752cef25310176349Romain Guy        final int count = strokes.size();
14082f3495b146b267f3786997752cef25310176349Romain Guy
14182f3495b146b267f3786997752cef25310176349Romain Guy        for (int i = 0; i < count; i++) {
14282f3495b146b267f3786997752cef25310176349Romain Guy            path.addPath(strokes.get(i).toPath(width - 2 * edge, height - 2 * edge, numSample));
14382f3495b146b267f3786997752cef25310176349Romain Guy        }
14482f3495b146b267f3786997752cef25310176349Romain Guy
14582f3495b146b267f3786997752cef25310176349Romain Guy        return path;
14682f3495b146b267f3786997752cef25310176349Romain Guy    }
14782f3495b146b267f3786997752cef25310176349Romain Guy
14835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
14935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * Set the id of the gesture
15035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
15135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param id
15235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
15335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    void setID(long id) {
15435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        mGestureID = id;
1556e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
15635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
15735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
15835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the id of the gesture
15935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
1606e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    public long getID() {
16135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return mGestureID;
1626e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
16335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
1646e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    /**
1656e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     * draw the gesture
16635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
1676e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     * @param canvas
1686e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     */
16935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    void draw(Canvas canvas, Paint paint) {
170c534727972c3835ed997e84a349f259915ef2cddRomain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
171c534727972c3835ed997e84a349f259915ef2cddRomain Guy        final int count = strokes.size();
172c534727972c3835ed997e84a349f259915ef2cddRomain Guy
17335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < count; i++) {
174c534727972c3835ed997e84a349f259915ef2cddRomain Guy            strokes.get(i).draw(canvas, paint);
1756e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        }
1766e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
17735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
1786e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    /**
17935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * Create a bitmap of the gesture with a transparent background
18035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
18135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param width width of the target bitmap
18235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param height height of the target bitmap
18335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param edge the edge
18435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param numSample
18535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param color
18635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the bitmap
187935fd37d27804539b141fa074c060d2c15524424Yang Li     */
18835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public Bitmap toBitmap(int width, int height, int edge, int numSample, int color) {
189b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
190b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Canvas canvas = new Canvas(bitmap);
191b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
19235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        canvas.translate(edge, edge);
193b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
194b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Paint paint = new Paint();
19535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS);
19635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setDither(BITMAP_RENDERING_DITHER);
19735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setColor(color);
19835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setStyle(Paint.Style.STROKE);
19935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setStrokeJoin(Paint.Join.ROUND);
20035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setStrokeCap(Paint.Cap.ROUND);
20135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setStrokeWidth(BITMAP_RENDERING_WIDTH);
202c534727972c3835ed997e84a349f259915ef2cddRomain Guy
203c534727972c3835ed997e84a349f259915ef2cddRomain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
204c534727972c3835ed997e84a349f259915ef2cddRomain Guy        final int count = strokes.size();
205c534727972c3835ed997e84a349f259915ef2cddRomain Guy
20635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < count; i++) {
207c534727972c3835ed997e84a349f259915ef2cddRomain Guy            Path path = strokes.get(i).toPath(width - 2 * edge, height - 2 * edge, numSample);
20835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            canvas.drawPath(path, paint);
209935fd37d27804539b141fa074c060d2c15524424Yang Li        }
21035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
21135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return bitmap;
212935fd37d27804539b141fa074c060d2c15524424Yang Li    }
21335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
214935fd37d27804539b141fa074c060d2c15524424Yang Li    /**
21535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * Create a bitmap of the gesture with a transparent background
21635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
21735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param width
21835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param height
2196e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     * @param edge
22035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param color
22135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the bitmap
2226e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato     */
22335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public Bitmap toBitmap(int width, int height, int edge, int color) {
224b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
225b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Canvas canvas = new Canvas(bitmap);
226b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
22735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        canvas.translate(edge, edge);
228b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
229b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Paint paint = new Paint();
23035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS);
23135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setDither(BITMAP_RENDERING_DITHER);
23235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setColor(color);
2336e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        paint.setStyle(Paint.Style.STROKE);
2346e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        paint.setStrokeJoin(Paint.Join.ROUND);
2356e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        paint.setStrokeCap(Paint.Cap.ROUND);
23635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        paint.setStrokeWidth(BITMAP_RENDERING_WIDTH);
237b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
238b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
239b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final int count = strokes.size();
240b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
24135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < count; i++) {
242b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            strokes.get(i).draw(canvas, paint);
24335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
24435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
2456e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        return bitmap;
2466e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
24735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
248b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy    void serialize(DataOutputStream out) throws IOException {
249b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final ArrayList<GestureStroke> strokes = mStrokes;
250b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final int count = strokes.size();
251b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
252b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        // Write gesture ID
253b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        out.writeLong(mGestureID);
254b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        // Write number of strokes
255b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        out.writeInt(count);
256b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
25735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < count; i++) {
258b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            strokes.get(i).serialize(out);
2596e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        }
2606e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
26135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
262b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy    static Gesture deserialize(DataInputStream in) throws IOException {
263b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final Gesture gesture = new Gesture();
264b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
265b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        // Gesture ID
266b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        gesture.mGestureID = in.readLong();
267b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        // Number of strokes
268b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final int count = in.readInt();
269b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
270b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        for (int i = 0; i < count; i++) {
271b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            gesture.addStroke(GestureStroke.deserialize(in));
2726e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        }
273b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
274b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        return gesture;
2756e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
27635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
27735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    public static final Parcelable.Creator<Gesture> CREATOR = new Parcelable.Creator<Gesture>() {
2786e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        public Gesture createFromParcel(Parcel in) {
279b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            Gesture gesture = null;
280b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            final long gestureID = in.readLong();
281b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
282b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            final DataInputStream inStream = new DataInputStream(
283b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy                    new ByteArrayInputStream(in.createByteArray()));
284b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
285b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            try {
286b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy                gesture = deserialize(inStream);
287b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            } catch (IOException e) {
288db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy                Log.e(GestureConstants.LOG_TAG, "Error reading Gesture from parcel:", e);
289b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            } finally {
290b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy                GestureUtilities.closeStream(inStream);
291b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            }
292b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
293b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            if (gesture != null) {
294b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy                gesture.mGestureID = gestureID;
295b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            }
296b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
29735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            return gesture;
2986e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        }
29935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3006e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        public Gesture[] newArray(int size) {
3016e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato            return new Gesture[size];
3026e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato        }
3036e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    };
30435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3056e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    public void writeToParcel(Parcel out, int flags) {
306b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        out.writeLong(mGestureID);
307b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
308b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        boolean result = false;
309b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final ByteArrayOutputStream byteStream =
310b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy                new ByteArrayOutputStream(GestureConstants.IO_BUFFER_SIZE);
311b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        final DataOutputStream outStream = new DataOutputStream(byteStream);
312b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
313b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        try {
314b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            serialize(outStream);
315b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            result = true;
316b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        } catch (IOException e) {
317db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy            Log.e(GestureConstants.LOG_TAG, "Error writing Gesture to parcel:", e);
318b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        } finally {
319b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            GestureUtilities.closeStream(outStream);
320b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            GestureUtilities.closeStream(byteStream);
321b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        }
322b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
323b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        if (result) {
324b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy            out.writeByteArray(byteStream.toByteArray());
325b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        }
3266e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
32735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3286e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    public int describeContents() {
329b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        return 0;
3306e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato    }
3316e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato}
332b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
333