diff options
author | Romain Guy <romainguy@android.com> | 2009-05-21 16:23:21 -0700 |
---|---|---|
committer | Romain Guy <romainguy@android.com> | 2009-05-21 18:12:56 -0700 |
commit | db567c390bd56c05614eaa83c02dbb99f97ad9cc (patch) | |
tree | 86399406ca7a53c3d902b3863bf7a944cb7c5c3f /core/java/android/gesture/GestureStroke.java | |
parent | 384bfa270cdcb5dc3bc9ec396b783e25eb2d9b4d (diff) | |
download | frameworks_base-db567c390bd56c05614eaa83c02dbb99f97ad9cc.zip frameworks_base-db567c390bd56c05614eaa83c02dbb99f97ad9cc.tar.gz frameworks_base-db567c390bd56c05614eaa83c02dbb99f97ad9cc.tar.bz2 |
Move the Gestures API to the framework in android.gesture.
Diffstat (limited to 'core/java/android/gesture/GestureStroke.java')
-rw-r--r-- | core/java/android/gesture/GestureStroke.java | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/core/java/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java new file mode 100644 index 0000000..5160a76 --- /dev/null +++ b/core/java/android/gesture/GestureStroke.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2008-2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gesture; + +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; + +import java.io.IOException; +import java.io.DataOutputStream; +import java.io.DataInputStream; +import java.util.ArrayList; + +/** + * A gesture stroke started on a touch down and ended on a touch up. + */ +public class GestureStroke { + public final RectF boundingBox; + + public final float length; + public final float[] points; + + private final long[] timestamps; + private Path mCachedPath; + + /** + * Construct a gesture stroke from a list of gesture points + * + * @param points + */ + public GestureStroke(ArrayList<GesturePoint> points) { + final int count = points.size(); + final float[] tmpPoints = new float[count * 2]; + final long[] times = new long[count]; + + RectF bx = null; + float len = 0; + int index = 0; + + for (int i = 0; i < count; i++) { + final GesturePoint p = points.get(i); + tmpPoints[i * 2] = p.x; + tmpPoints[i * 2 + 1] = p.y; + times[index] = p.timestamp; + + if (bx == null) { + bx = new RectF(); + bx.top = p.y; + bx.left = p.x; + bx.right = p.x; + bx.bottom = p.y; + len = 0; + } else { + len += Math.sqrt(Math.pow(p.x - tmpPoints[(i - 1) * 2], 2) + + Math.pow(p.y - tmpPoints[(i -1 ) * 2 + 1], 2)); + bx.union(p.x, p.y); + } + index++; + } + + timestamps = times; + this.points = tmpPoints; + boundingBox = bx; + length = len; + } + + /** + * Draw the gesture with a given canvas and paint + * + * @param canvas + */ + void draw(Canvas canvas, Paint paint) { + if (mCachedPath == null) { + final float[] localPoints = points; + final int count = localPoints.length; + + Path path = null; + + float mX = 0; + float mY = 0; + + for (int i = 0; i < count; i += 2) { + float x = localPoints[i]; + float y = localPoints[i + 1]; + if (path == null) { + path = new Path(); + path.moveTo(x, y); + mX = x; + mY = y; + } else { + float dx = Math.abs(x - mX); + float dy = Math.abs(y - mY); + if (dx >= 3 || dy >= 3) { + path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); + mX = x; + mY = y; + } + } + } + + mCachedPath = path; + } + + canvas.drawPath(mCachedPath, paint); + } + + /** + * Convert the stroke to a Path based on the number of points + * + * @param width the width of the bounding box of the target path + * @param height the height of the bounding box of the target path + * @param numSample the number of points needed + * + * @return the path + */ + public Path toPath(float width, float height, int numSample) { + final float[] pts = GestureUtilities.temporalSampling(this, numSample); + final RectF rect = boundingBox; + + final Matrix matrix = new Matrix(); + matrix.setTranslate(-rect.left, -rect.top); + matrix.postScale(width / rect.width(), height / rect.height()); + matrix.mapPoints(pts); + + float mX = 0; + float mY = 0; + + Path path = null; + + final int count = pts.length; + + for (int i = 0; i < count; i += 2) { + float x = pts[i]; + float y = pts[i + 1]; + if (path == null) { + path = new Path(); + path.moveTo(x, y); + mX = x; + mY = y; + } else { + float dx = Math.abs(x - mX); + float dy = Math.abs(y - mY); + if (dx >= GestureOverlayView.TOUCH_TOLERANCE || + dy >= GestureOverlayView.TOUCH_TOLERANCE) { + path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); + mX = x; + mY = y; + } + } + } + + return path; + } + + void serialize(DataOutputStream out) throws IOException { + final float[] pts = points; + final long[] times = timestamps; + final int count = points.length; + + // Write number of points + out.writeInt(count / 2); + + for (int i = 0; i < count; i += 2) { + // Write X + out.writeFloat(pts[i]); + // Write Y + out.writeFloat(pts[i + 1]); + // Write timestamp + out.writeLong(times[i / 2]); + } + } + + static GestureStroke deserialize(DataInputStream in) throws IOException { + // Number of points + final int count = in.readInt(); + + final ArrayList<GesturePoint> points = new ArrayList<GesturePoint>(count); + for (int i = 0; i < count; i++) { + points.add(GesturePoint.deserialize(in)); + } + + return new GestureStroke(points); + } + + /** + * Invalidate the cached path that is used to render the stroke + */ + public void clearPath() { + if (mCachedPath != null) mCachedPath.rewind(); + } + + /** + * Compute an oriented bounding box of the stroke + * @return OrientedBoundingBox + */ + public OrientedBoundingBox computeOrientedBoundingBox() { + return GestureUtilities.computeOrientedBoundingBox(points); + } +} |