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; 34ef0e9ae0ddbf70f5e30fbfbffe379e3026b9dc13Romain Guyimport java.util.concurrent.atomic.AtomicInteger; 356e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato 366e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato/** 376fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * A gesture is a hand-drawn shape on a touch screen. It can have one or multiple strokes. 386fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * Each stroke is a sequence of timed points. A user-defined gesture can be recognized by 3902739a8eecce26783350041da332f8daf6691e25Romain Guy * a GestureLibrary. 406e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato */ 416e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato 426e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onoratopublic class Gesture implements Parcelable { 4335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final long GESTURE_ID_BASE = System.currentTimeMillis(); 4435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 4535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final int BITMAP_RENDERING_WIDTH = 2; 4635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 4735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final boolean BITMAP_RENDERING_ANTIALIAS = true; 4835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final boolean BITMAP_RENDERING_DITHER = true; 4935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 50ef0e9ae0ddbf70f5e30fbfbffe379e3026b9dc13Romain Guy private static final AtomicInteger sGestureCount = new AtomicInteger(0); 5135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 529ffe1ae56bf495b1ada1e9c1da523db0677d98b7Romain Guy private final RectF mBoundingBox = new RectF(); 5335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 5435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // the same as its instance ID 5535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private long mGestureID; 5635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 57c534727972c3835ed997e84a349f259915ef2cddRomain Guy private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>(); 586e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato 596e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public Gesture() { 60ef0e9ae0ddbf70f5e30fbfbffe379e3026b9dc13Romain Guy mGestureID = GESTURE_ID_BASE + sGestureCount.incrementAndGet(); 616e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 626e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato 636fc1f151341c628125e7d20c1667a23862f32ce4Yang Li @Override 646fc1f151341c628125e7d20c1667a23862f32ce4Yang Li public Object clone() { 656fc1f151341c628125e7d20c1667a23862f32ce4Yang Li Gesture gesture = new Gesture(); 666fc1f151341c628125e7d20c1667a23862f32ce4Yang Li gesture.mBoundingBox.set(mBoundingBox.left, mBoundingBox.top, 676fc1f151341c628125e7d20c1667a23862f32ce4Yang Li mBoundingBox.right, mBoundingBox.bottom); 686fc1f151341c628125e7d20c1667a23862f32ce4Yang Li final int count = mStrokes.size(); 696fc1f151341c628125e7d20c1667a23862f32ce4Yang Li for (int i = 0; i < count; i++) { 706fc1f151341c628125e7d20c1667a23862f32ce4Yang Li GestureStroke stroke = mStrokes.get(i); 716fc1f151341c628125e7d20c1667a23862f32ce4Yang Li gesture.mStrokes.add((GestureStroke)stroke.clone()); 726fc1f151341c628125e7d20c1667a23862f32ce4Yang Li } 736fc1f151341c628125e7d20c1667a23862f32ce4Yang Li return gesture; 746fc1f151341c628125e7d20c1667a23862f32ce4Yang Li } 756fc1f151341c628125e7d20c1667a23862f32ce4Yang Li 7635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 7735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return all the strokes of the gesture 7835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 7935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li public ArrayList<GestureStroke> getStrokes() { 8035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return mStrokes; 81935fd37d27804539b141fa074c060d2c15524424Yang Li } 8235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 8335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 8435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return the number of strokes included by this gesture 8535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 8635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li public int getStrokesCount() { 8735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return mStrokes.size(); 886e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 896e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato 9035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 916fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * Adds a stroke to the gesture. 9235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 9335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param stroke 9435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 9535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li public void addStroke(GestureStroke stroke) { 9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mStrokes.add(stroke); 979ffe1ae56bf495b1ada1e9c1da523db0677d98b7Romain Guy mBoundingBox.union(stroke.boundingBox); 986e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 996e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato 1006e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato /** 1016fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * Calculates the total length of the gesture. When there are multiple strokes in 1026fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * the gesture, this returns the sum of the lengths of all the strokes. 10335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 1046e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato * @return the length of the gesture 1056e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato */ 1066e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public float getLength() { 10735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li int len = 0; 108c534727972c3835ed997e84a349f259915ef2cddRomain Guy final ArrayList<GestureStroke> strokes = mStrokes; 109c534727972c3835ed997e84a349f259915ef2cddRomain Guy final int count = strokes.size(); 110c534727972c3835ed997e84a349f259915ef2cddRomain Guy 11135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li for (int i = 0; i < count; i++) { 112c534727972c3835ed997e84a349f259915ef2cddRomain Guy len += strokes.get(i).length; 11335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 114c534727972c3835ed997e84a349f259915ef2cddRomain Guy 11535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return len; 1166e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 11735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 11835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 11935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return the bounding box of the gesture 12035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 12135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li public RectF getBoundingBox() { 12235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return mBoundingBox; 1236e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 12435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 12582f3495b146b267f3786997752cef25310176349Romain Guy public Path toPath() { 12682f3495b146b267f3786997752cef25310176349Romain Guy return toPath(null); 12782f3495b146b267f3786997752cef25310176349Romain Guy } 12882f3495b146b267f3786997752cef25310176349Romain Guy 12982f3495b146b267f3786997752cef25310176349Romain Guy public Path toPath(Path path) { 13082f3495b146b267f3786997752cef25310176349Romain Guy if (path == null) path = new Path(); 13182f3495b146b267f3786997752cef25310176349Romain Guy 13282f3495b146b267f3786997752cef25310176349Romain Guy final ArrayList<GestureStroke> strokes = mStrokes; 13382f3495b146b267f3786997752cef25310176349Romain Guy final int count = strokes.size(); 13482f3495b146b267f3786997752cef25310176349Romain Guy 13582f3495b146b267f3786997752cef25310176349Romain Guy for (int i = 0; i < count; i++) { 13682f3495b146b267f3786997752cef25310176349Romain Guy path.addPath(strokes.get(i).getPath()); 13782f3495b146b267f3786997752cef25310176349Romain Guy } 13882f3495b146b267f3786997752cef25310176349Romain Guy 13982f3495b146b267f3786997752cef25310176349Romain Guy return path; 14082f3495b146b267f3786997752cef25310176349Romain Guy } 14182f3495b146b267f3786997752cef25310176349Romain Guy 14282f3495b146b267f3786997752cef25310176349Romain Guy public Path toPath(int width, int height, int edge, int numSample) { 14382f3495b146b267f3786997752cef25310176349Romain Guy return toPath(null, width, height, edge, numSample); 14482f3495b146b267f3786997752cef25310176349Romain Guy } 14582f3495b146b267f3786997752cef25310176349Romain Guy 14682f3495b146b267f3786997752cef25310176349Romain Guy public Path toPath(Path path, int width, int height, int edge, int numSample) { 14782f3495b146b267f3786997752cef25310176349Romain Guy if (path == null) path = new Path(); 14882f3495b146b267f3786997752cef25310176349Romain Guy 14982f3495b146b267f3786997752cef25310176349Romain Guy final ArrayList<GestureStroke> strokes = mStrokes; 15082f3495b146b267f3786997752cef25310176349Romain Guy final int count = strokes.size(); 15182f3495b146b267f3786997752cef25310176349Romain Guy 15282f3495b146b267f3786997752cef25310176349Romain Guy for (int i = 0; i < count; i++) { 15382f3495b146b267f3786997752cef25310176349Romain Guy path.addPath(strokes.get(i).toPath(width - 2 * edge, height - 2 * edge, numSample)); 15482f3495b146b267f3786997752cef25310176349Romain Guy } 15582f3495b146b267f3786997752cef25310176349Romain Guy 15682f3495b146b267f3786997752cef25310176349Romain Guy return path; 15782f3495b146b267f3786997752cef25310176349Romain Guy } 15882f3495b146b267f3786997752cef25310176349Romain Guy 15935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 1606fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * Sets the id of the gesture. 16135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 16235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param id 16335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 16435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li void setID(long id) { 16535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mGestureID = id; 1666e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 16735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 16835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 16935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return the id of the gesture 17035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 1716e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public long getID() { 17235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return mGestureID; 1736e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 17435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 1756e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato /** 1766fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * Creates a bitmap of the gesture with a transparent background. 17735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 17835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param width width of the target bitmap 17935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param height height of the target bitmap 18035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param edge the edge 18135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param numSample 18235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param color 18335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return the bitmap 184935fd37d27804539b141fa074c060d2c15524424Yang Li */ 18535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li public Bitmap toBitmap(int width, int height, int edge, int numSample, int color) { 186b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 187b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final Canvas canvas = new Canvas(bitmap); 188b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 18935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li canvas.translate(edge, edge); 190b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 191b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final Paint paint = new Paint(); 19235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS); 19335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setDither(BITMAP_RENDERING_DITHER); 19435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setColor(color); 19535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setStyle(Paint.Style.STROKE); 19635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setStrokeJoin(Paint.Join.ROUND); 19735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setStrokeCap(Paint.Cap.ROUND); 19835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setStrokeWidth(BITMAP_RENDERING_WIDTH); 199c534727972c3835ed997e84a349f259915ef2cddRomain Guy 200c534727972c3835ed997e84a349f259915ef2cddRomain Guy final ArrayList<GestureStroke> strokes = mStrokes; 201c534727972c3835ed997e84a349f259915ef2cddRomain Guy final int count = strokes.size(); 202c534727972c3835ed997e84a349f259915ef2cddRomain Guy 20335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li for (int i = 0; i < count; i++) { 204c534727972c3835ed997e84a349f259915ef2cddRomain Guy Path path = strokes.get(i).toPath(width - 2 * edge, height - 2 * edge, numSample); 20535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li canvas.drawPath(path, paint); 206935fd37d27804539b141fa074c060d2c15524424Yang Li } 20735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 20835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return bitmap; 209935fd37d27804539b141fa074c060d2c15524424Yang Li } 21035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 211935fd37d27804539b141fa074c060d2c15524424Yang Li /** 2126fc1f151341c628125e7d20c1667a23862f32ce4Yang Li * Creates a bitmap of the gesture with a transparent background. 21335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 21435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param width 21535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param height 216cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy * @param inset 21735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param color 21835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return the bitmap 2196e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato */ 220cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy public Bitmap toBitmap(int width, int height, int inset, int color) { 221cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy final Bitmap bitmap = Bitmap.createBitmap(width, height, 222cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy Bitmap.Config.ARGB_8888); 223b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final Canvas canvas = new Canvas(bitmap); 224b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 225b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final Paint paint = new Paint(); 22635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS); 22735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setDither(BITMAP_RENDERING_DITHER); 22835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setColor(color); 2296e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato paint.setStyle(Paint.Style.STROKE); 2306e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato paint.setStrokeJoin(Paint.Join.ROUND); 2316e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato paint.setStrokeCap(Paint.Cap.ROUND); 23235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li paint.setStrokeWidth(BITMAP_RENDERING_WIDTH); 233b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 234cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy final Path path = toPath(); 235cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy final RectF bounds = new RectF(); 236cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy path.computeBounds(bounds, true); 237b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 238cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy final float sx = (width - 2 * inset) / bounds.width(); 239cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy final float sy = (height - 2 * inset) / bounds.height(); 240cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy final float scale = sx > sy ? sy : sx; 241cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy paint.setStrokeWidth(2.0f / scale); 242cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy 243cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy path.offset(-bounds.left + (width - bounds.width() * scale) / 2.0f, 244cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy -bounds.top + (height - bounds.height() * scale) / 2.0f); 245cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy 246cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy canvas.translate(inset, inset); 247cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy canvas.scale(scale, scale); 248cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy 249cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy canvas.drawPath(path, paint); 25035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 2516e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato return bitmap; 2526e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 25335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 254b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy void serialize(DataOutputStream out) throws IOException { 255b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final ArrayList<GestureStroke> strokes = mStrokes; 256b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final int count = strokes.size(); 257b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 258b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy // Write gesture ID 259b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy out.writeLong(mGestureID); 260b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy // Write number of strokes 261b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy out.writeInt(count); 262b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 26335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li for (int i = 0; i < count; i++) { 264b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy strokes.get(i).serialize(out); 2656e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 2666e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 26735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 268b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy static Gesture deserialize(DataInputStream in) throws IOException { 269b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final Gesture gesture = new Gesture(); 270b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 271b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy // Gesture ID 272b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy gesture.mGestureID = in.readLong(); 273b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy // Number of strokes 274b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final int count = in.readInt(); 275b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 276b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy for (int i = 0; i < count; i++) { 277b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy gesture.addStroke(GestureStroke.deserialize(in)); 2786e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 279b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 280b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy return gesture; 2816e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 28235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 28335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li public static final Parcelable.Creator<Gesture> CREATOR = new Parcelable.Creator<Gesture>() { 2846e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public Gesture createFromParcel(Parcel in) { 285b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy Gesture gesture = null; 286b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final long gestureID = in.readLong(); 287b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 288b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final DataInputStream inStream = new DataInputStream( 289b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy new ByteArrayInputStream(in.createByteArray())); 290b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 291b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy try { 292b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy gesture = deserialize(inStream); 293b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } catch (IOException e) { 294db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy Log.e(GestureConstants.LOG_TAG, "Error reading Gesture from parcel:", e); 295b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } finally { 29646c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.closeStream(inStream); 297b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } 298b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 299b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy if (gesture != null) { 300b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy gesture.mGestureID = gestureID; 301b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } 302b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 30335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return gesture; 3046e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 30535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3066e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public Gesture[] newArray(int size) { 3076e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato return new Gesture[size]; 3086e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 3096e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato }; 31035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3116e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public void writeToParcel(Parcel out, int flags) { 312b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy out.writeLong(mGestureID); 313b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 314b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy boolean result = false; 315b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final ByteArrayOutputStream byteStream = 316b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy new ByteArrayOutputStream(GestureConstants.IO_BUFFER_SIZE); 317b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy final DataOutputStream outStream = new DataOutputStream(byteStream); 318b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 319b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy try { 320b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy serialize(outStream); 321b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy result = true; 322b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } catch (IOException e) { 323db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy Log.e(GestureConstants.LOG_TAG, "Error writing Gesture to parcel:", e); 324b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } finally { 32546c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.closeStream(outStream); 32646c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.closeStream(byteStream); 327b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } 328b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 329b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy if (result) { 330b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy out.writeByteArray(byteStream.toByteArray()); 331b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy } 3326e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 33335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3346e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato public int describeContents() { 335b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy return 0; 3366e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato } 3376e93a3db56d6add29b43077718a4cad9ccfc047fJoe Onorato} 338b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 339