From cb3bba3c4ee4652e12c81185ab9a648db20bb0dd Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Mon, 13 May 2013 13:12:12 +0900 Subject: Rename GesturePreviewTrail.java -> GestureTrail.java Try reducing some confusions between GesturePreviewTrail.java and GestureTrailsPreview.java Change-Id: I5fe2ee740cf1b32210530188153f6f6937e34b68 --- .../inputmethod/keyboard/MainKeyboardView.java | 6 +- .../inputmethod/keyboard/PointerTracker.java | 8 +- .../keyboard/internal/GesturePreviewTrail.java | 298 --------------------- .../internal/GestureStrokeWithPreviewPoints.java | 22 +- .../keyboard/internal/GestureTrail.java | 298 +++++++++++++++++++++ .../keyboard/internal/GestureTrailsPreview.java | 62 +++-- 6 files changed, 346 insertions(+), 348 deletions(-) delete mode 100644 java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java create mode 100644 java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index a0ac47535..3201d2e5b 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -910,10 +910,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mSlidingKeyInputPreview.dismissSlidingKeyInputPreview(); } - public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail, + public void setGesturePreviewMode(final boolean drawsGestureTrail, final boolean drawsGestureFloatingPreviewText) { mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText); - mGestureTrailsPreview.setPreviewEnabled(drawsGesturePreviewTrail); + mGestureTrailsPreview.setPreviewEnabled(drawsGestureTrail); } public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { @@ -927,7 +927,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } @Override - public void showGesturePreviewTrail(final PointerTracker tracker) { + public void showGestureTrail(final PointerTracker tracker) { locatePreviewPlacerView(); mGestureFloatingPreviewText.setPreviewPosition(tracker); mGestureTrailsPreview.setPreviewPosition(tracker); diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 2d791648e..5e4b1a58d 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -84,7 +84,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { public void dismissKeyPreview(PointerTracker tracker); public void showSlidingKeyInputPreview(PointerTracker tracker); public void dismissSlidingKeyInputPreview(); - public void showGesturePreviewTrail(PointerTracker tracker); + public void showGestureTrail(PointerTracker tracker); } public interface TimerProxy { @@ -737,7 +737,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { dismissAllMoreKeysPanels(); } mTimerProxy.cancelLongPressTimer(); - mDrawingProxy.showGesturePreviewTrail(this); + mDrawingProxy.showGestureTrail(this); } public void updateBatchInputByTimer(final long eventTime) { @@ -753,7 +753,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (mIsTrackingForActionDisabled) { return; } - mDrawingProxy.showGesturePreviewTrail(this); + mDrawingProxy.showGestureTrail(this); } private void updateBatchInput(final long eventTime) { @@ -794,7 +794,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (mIsTrackingForActionDisabled) { return; } - mDrawingProxy.showGesturePreviewTrail(this); + mDrawingProxy.showGestureTrail(this); } private void cancelBatchInput() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java deleted file mode 100644 index 761d9dcd6..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 2012 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 com.android.inputmethod.keyboard.internal; - -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.os.SystemClock; - -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.ResizableIntArray; - -/* - * @attr ref R.styleable#MainKeyboardView_gesturePreviewTrailFadeoutStartDelay - * @attr ref R.styleable#MainKeyboardView_gesturePreviewTrailFadeoutDuration - * @attr ref R.styleable#MainKeyboardView_gesturePreviewTrailUpdateInterval - * @attr ref R.styleable#MainKeyboardView_gesturePreviewTrailColor - * @attr ref R.styleable#MainKeyboardView_gesturePreviewTrailWidth - */ -final class GesturePreviewTrail { - public static final boolean DBG_SHOW_POINTS = false; - public static final int POINT_TYPE_SAMPLED = 0; - public static final int POINT_TYPE_INTERPOLATED = 1; - public static final int POINT_TYPE_COMPROMISED = 2; - - private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY; - - // These three {@link ResizableIntArray}s should be synchronized by {@link #mEventTimes}. - private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mPointTypes = new ResizableIntArray( - DBG_SHOW_POINTS ? DEFAULT_CAPACITY : 0); - private int mCurrentStrokeId = -1; - // The wall time of the zero value in {@link #mEventTimes} - private long mCurrentTimeBase; - private int mTrailStartIndex; - private int mLastInterpolatedDrawIndex; - - static final class Params { - public final int mTrailColor; - public final float mTrailStartWidth; - public final float mTrailEndWidth; - public final float mTrailBodyRatio; - public boolean mTrailShadowEnabled; - public final float mTrailShadowRatio; - public final int mFadeoutStartDelay; - public final int mFadeoutDuration; - public final int mUpdateInterval; - - public final int mTrailLingerDuration; - - public Params(final TypedArray mainKeyboardViewAttr) { - mTrailColor = mainKeyboardViewAttr.getColor( - R.styleable.MainKeyboardView_gesturePreviewTrailColor, 0); - mTrailStartWidth = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_gesturePreviewTrailStartWidth, 0.0f); - mTrailEndWidth = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_gesturePreviewTrailEndWidth, 0.0f); - final int PERCENTAGE_INT = 100; - mTrailBodyRatio = (float)mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gesturePreviewTrailBodyRatio, PERCENTAGE_INT) - / (float)PERCENTAGE_INT; - final int trailShadowRatioInt = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gesturePreviewTrailShadowRatio, 0); - mTrailShadowEnabled = (trailShadowRatioInt > 0); - mTrailShadowRatio = (float)trailShadowRatioInt / (float)PERCENTAGE_INT; - mFadeoutStartDelay = DBG_SHOW_POINTS ? 2000 : mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gesturePreviewTrailFadeoutStartDelay, 0); - mFadeoutDuration = DBG_SHOW_POINTS ? 200 : mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gesturePreviewTrailFadeoutDuration, 0); - mTrailLingerDuration = mFadeoutStartDelay + mFadeoutDuration; - mUpdateInterval = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gesturePreviewTrailUpdateInterval, 0); - } - } - - // Use this value as imaginary zero because x-coordinates may be zero. - private static final int DOWN_EVENT_MARKER = -128; - - private static int markAsDownEvent(final int xCoord) { - return DOWN_EVENT_MARKER - xCoord; - } - - private static boolean isDownEventXCoord(final int xCoordOrMark) { - return xCoordOrMark <= DOWN_EVENT_MARKER; - } - - private static int getXCoordValue(final int xCoordOrMark) { - return isDownEventXCoord(xCoordOrMark) - ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark; - } - - public void addStroke(final GestureStrokeWithPreviewPoints stroke, final long downTime) { - synchronized (mEventTimes) { - addStrokeLocked(stroke, downTime); - } - } - - private void addStrokeLocked(final GestureStrokeWithPreviewPoints stroke, final long downTime) { - final int trailSize = mEventTimes.getLength(); - stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates); - if (mEventTimes.getLength() == trailSize) { - return; - } - final int[] eventTimes = mEventTimes.getPrimitiveArray(); - final int strokeId = stroke.getGestureStrokeId(); - // Because interpolation algorithm in {@link GestureStrokeWithPreviewPoints} can't determine - // the interpolated points in the last segment of gesture stroke, it may need recalculation - // of interpolation when new segments are added to the stroke. - // {@link #mLastInterpolatedDrawIndex} holds the start index of the last segment. It may - // be updated by the interpolation - // {@link GestureStrokeWithPreviewPoints#interpolatePreviewStroke} - // or by animation {@link #drawGestureTrail(Canvas,Paint,Rect,Params)} below. - final int lastInterpolatedIndex = (strokeId == mCurrentStrokeId) - ? mLastInterpolatedDrawIndex : trailSize; - mLastInterpolatedDrawIndex = stroke.interpolateStrokeAndReturnStartIndexOfLastSegment( - lastInterpolatedIndex, mEventTimes, mXCoordinates, mYCoordinates, mPointTypes); - if (strokeId != mCurrentStrokeId) { - final int elapsedTime = (int)(downTime - mCurrentTimeBase); - for (int i = mTrailStartIndex; i < trailSize; i++) { - // Decay the previous strokes' event times. - eventTimes[i] -= elapsedTime; - } - final int[] xCoords = mXCoordinates.getPrimitiveArray(); - final int downIndex = trailSize; - xCoords[downIndex] = markAsDownEvent(xCoords[downIndex]); - mCurrentTimeBase = downTime - eventTimes[downIndex]; - mCurrentStrokeId = strokeId; - } - } - - /** - * Calculate the alpha of a gesture trail. - * A gesture trail starts from fully opaque. After mFadeStartDelay has been passed, the alpha - * of a trail reduces in proportion to the elapsed time. Then after mFadeDuration has been - * passed, a trail becomes fully transparent. - * - * @param elapsedTime the elapsed time since a trail has been made. - * @param params gesture trail display parameters - * @return the width of a gesture trail - */ - private static int getAlpha(final int elapsedTime, final Params params) { - if (elapsedTime < params.mFadeoutStartDelay) { - return Constants.Color.ALPHA_OPAQUE; - } - final int decreasingAlpha = Constants.Color.ALPHA_OPAQUE - * (elapsedTime - params.mFadeoutStartDelay) - / params.mFadeoutDuration; - return Constants.Color.ALPHA_OPAQUE - decreasingAlpha; - } - - /** - * Calculate the width of a gesture trail. - * A gesture trail starts from the width of mTrailStartWidth and reduces its width in proportion - * to the elapsed time. After mTrailEndWidth has been passed, the width becomes mTraiLEndWidth. - * - * @param elapsedTime the elapsed time since a trail has been made. - * @param params gesture trail display parameters - * @return the width of a gesture trail - */ - private static float getWidth(final int elapsedTime, final Params params) { - final float deltaWidth = params.mTrailStartWidth - params.mTrailEndWidth; - return params.mTrailStartWidth - (deltaWidth * elapsedTime) / params.mTrailLingerDuration; - } - - private final RoundedLine mRoundedLine = new RoundedLine(); - private final Rect mRoundedLineBounds = new Rect(); - - /** - * Draw gesture preview trail - * @param canvas The canvas to draw the gesture preview trail - * @param paint The paint object to be used to draw the gesture preview trail - * @param outBoundsRect the bounding box of this gesture trail drawing - * @param params The drawing parameters of gesture preview trail - * @return true if some gesture preview trails remain to be drawn - */ - public boolean drawGestureTrail(final Canvas canvas, final Paint paint, - final Rect outBoundsRect, final Params params) { - synchronized (mEventTimes) { - return drawGestureTrailLocked(canvas, paint, outBoundsRect, params); - } - } - - private boolean drawGestureTrailLocked(final Canvas canvas, final Paint paint, - final Rect outBoundsRect, final Params params) { - // Initialize bounds rectangle. - outBoundsRect.setEmpty(); - final int trailSize = mEventTimes.getLength(); - if (trailSize == 0) { - return false; - } - - final int[] eventTimes = mEventTimes.getPrimitiveArray(); - final int[] xCoords = mXCoordinates.getPrimitiveArray(); - final int[] yCoords = mYCoordinates.getPrimitiveArray(); - final int[] pointTypes = mPointTypes.getPrimitiveArray(); - final int sinceDown = (int)(SystemClock.uptimeMillis() - mCurrentTimeBase); - int startIndex; - for (startIndex = mTrailStartIndex; startIndex < trailSize; startIndex++) { - final int elapsedTime = sinceDown - eventTimes[startIndex]; - // Skip too old trail points. - if (elapsedTime < params.mTrailLingerDuration) { - break; - } - } - mTrailStartIndex = startIndex; - - if (startIndex < trailSize) { - paint.setColor(params.mTrailColor); - paint.setStyle(Paint.Style.FILL); - final RoundedLine roundedLine = mRoundedLine; - int p1x = getXCoordValue(xCoords[startIndex]); - int p1y = yCoords[startIndex]; - final int lastTime = sinceDown - eventTimes[startIndex]; - float r1 = getWidth(lastTime, params) / 2.0f; - for (int i = startIndex + 1; i < trailSize; i++) { - final int elapsedTime = sinceDown - eventTimes[i]; - final int p2x = getXCoordValue(xCoords[i]); - final int p2y = yCoords[i]; - final float r2 = getWidth(elapsedTime, params) / 2.0f; - // Draw trail line only when the current point isn't a down point. - if (!isDownEventXCoord(xCoords[i])) { - final float body1 = r1 * params.mTrailBodyRatio; - final float body2 = r2 * params.mTrailBodyRatio; - final Path path = roundedLine.makePath(p1x, p1y, body1, p2x, p2y, body2); - if (path != null) { - roundedLine.getBounds(mRoundedLineBounds); - if (params.mTrailShadowEnabled) { - final float shadow2 = r2 * params.mTrailShadowRatio; - paint.setShadowLayer(shadow2, 0.0f, 0.0f, params.mTrailColor); - final int shadowInset = -(int)Math.ceil(shadow2); - mRoundedLineBounds.inset(shadowInset, shadowInset); - } - // Take union for the bounds. - outBoundsRect.union(mRoundedLineBounds); - final int alpha = getAlpha(elapsedTime, params); - paint.setAlpha(alpha); - canvas.drawPath(path, paint); - if (DBG_SHOW_POINTS) { - if (pointTypes[i] == POINT_TYPE_INTERPOLATED) { - paint.setColor(Color.RED); - } else if (pointTypes[i] == POINT_TYPE_SAMPLED) { - paint.setColor(0xFFA000FF); - } else { - paint.setColor(Color.GREEN); - } - canvas.drawCircle(p1x - 1, p1y - 1, 2, paint); - paint.setColor(params.mTrailColor); - } - } - } - p1x = p2x; - p1y = p2y; - r1 = r2; - } - } - - final int newSize = trailSize - startIndex; - if (newSize < startIndex) { - mTrailStartIndex = 0; - if (newSize > 0) { - System.arraycopy(eventTimes, startIndex, eventTimes, 0, newSize); - System.arraycopy(xCoords, startIndex, xCoords, 0, newSize); - System.arraycopy(yCoords, startIndex, yCoords, 0, newSize); - } - mEventTimes.setLength(newSize); - mXCoordinates.setLength(newSize); - mYCoordinates.setLength(newSize); - if (DBG_SHOW_POINTS) { - mPointTypes.setLength(newSize); - } - // The start index of the last segment of the stroke - // {@link mLastInterpolatedDrawIndex} should also be updated because all array - // elements have just been shifted for compaction or been zeroed. - mLastInterpolatedDrawIndex = Math.max(mLastInterpolatedDrawIndex - startIndex, 0); - } - return newSize > 0; - } -} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java index ccb8802c6..b31f00b62 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java @@ -63,18 +63,18 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { public GestureStrokePreviewParams(final TypedArray mainKeyboardViewAttr) { mMinSamplingDistance = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_gesturePreviewTrailMinSamplingDistance, + R.styleable.MainKeyboardView_gestureTrailMinSamplingDistance, (float)DEFAULT.mMinSamplingDistance); final int interpolationAngularDegree = mainKeyboardViewAttr.getInteger(R.styleable - .MainKeyboardView_gesturePreviewTrailMaxInterpolationAngularThreshold, 0); + .MainKeyboardView_gestureTrailMaxInterpolationAngularThreshold, 0); mMaxInterpolationAngularThreshold = (interpolationAngularDegree <= 0) ? DEFAULT.mMaxInterpolationAngularThreshold : degreeToRadian(interpolationAngularDegree); mMaxInterpolationDistanceThreshold = mainKeyboardViewAttr.getDimension(R.styleable - .MainKeyboardView_gesturePreviewTrailMaxInterpolationDistanceThreshold, + .MainKeyboardView_gestureTrailMaxInterpolationDistanceThreshold, (float)DEFAULT.mMaxInterpolationDistanceThreshold); mMaxInterpolationSegments = mainKeyboardViewAttr.getInteger( - R.styleable.MainKeyboardView_gesturePreviewTrailMaxInterpolationSegments, + R.styleable.MainKeyboardView_gestureTrailMaxInterpolationSegments, DEFAULT.mMaxInterpolationSegments); } } @@ -145,9 +145,9 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { * * @param lastInterpolatedIndex the start index of the last interpolated segment of * eventTimes, xCoords, and yCoords. - * @param eventTimes the event time array of gesture preview trail to be drawn. - * @param xCoords the x-coordinates array of gesture preview trail to be drawn. - * @param yCoords the y-coordinates array of gesture preview trail to be drawn. + * @param eventTimes the event time array of gesture trail to be drawn. + * @param xCoords the x-coordinates array of gesture trail to be drawn. + * @param yCoords the y-coordinates array of gesture trail to be drawn. * @return the start index of the last interpolated segment of input arrays. */ public int interpolateStrokeAndReturnStartIndexOfLastSegment(final int lastInterpolatedIndex, @@ -189,16 +189,16 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { eventTimes.add(d1, (int)(dt * t) + t1); xCoords.add(d1, (int)mInterpolator.mInterpolatedX); yCoords.add(d1, (int)mInterpolator.mInterpolatedY); - if (GesturePreviewTrail.DBG_SHOW_POINTS) { - types.add(d1, GesturePreviewTrail.POINT_TYPE_INTERPOLATED); + if (GestureTrail.DBG_SHOW_POINTS) { + types.add(d1, GestureTrail.POINT_TYPE_INTERPOLATED); } d1++; } eventTimes.add(d1, pt[p2]); xCoords.add(d1, px[p2]); yCoords.add(d1, py[p2]); - if (GesturePreviewTrail.DBG_SHOW_POINTS) { - types.add(d1, GesturePreviewTrail.POINT_TYPE_SAMPLED); + if (GestureTrail.DBG_SHOW_POINTS) { + types.add(d1, GestureTrail.POINT_TYPE_SAMPLED); } } return lastInterpolatedDrawIndex; diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java new file mode 100644 index 000000000..03dd1c372 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2012 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 com.android.inputmethod.keyboard.internal; + +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.os.SystemClock; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.ResizableIntArray; + +/* + * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutStartDelay + * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutDuration + * @attr ref R.styleable#MainKeyboardView_gestureTrailUpdateInterval + * @attr ref R.styleable#MainKeyboardView_gestureTrailColor + * @attr ref R.styleable#MainKeyboardView_gestureTrailWidth + */ +final class GestureTrail { + public static final boolean DBG_SHOW_POINTS = false; + public static final int POINT_TYPE_SAMPLED = 0; + public static final int POINT_TYPE_INTERPOLATED = 1; + public static final int POINT_TYPE_COMPROMISED = 2; + + private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY; + + // These three {@link ResizableIntArray}s should be synchronized by {@link #mEventTimes}. + private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); + private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); + private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); + private final ResizableIntArray mPointTypes = new ResizableIntArray( + DBG_SHOW_POINTS ? DEFAULT_CAPACITY : 0); + private int mCurrentStrokeId = -1; + // The wall time of the zero value in {@link #mEventTimes} + private long mCurrentTimeBase; + private int mTrailStartIndex; + private int mLastInterpolatedDrawIndex; + + static final class Params { + public final int mTrailColor; + public final float mTrailStartWidth; + public final float mTrailEndWidth; + public final float mTrailBodyRatio; + public boolean mTrailShadowEnabled; + public final float mTrailShadowRatio; + public final int mFadeoutStartDelay; + public final int mFadeoutDuration; + public final int mUpdateInterval; + + public final int mTrailLingerDuration; + + public Params(final TypedArray mainKeyboardViewAttr) { + mTrailColor = mainKeyboardViewAttr.getColor( + R.styleable.MainKeyboardView_gestureTrailColor, 0); + mTrailStartWidth = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_gestureTrailStartWidth, 0.0f); + mTrailEndWidth = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_gestureTrailEndWidth, 0.0f); + final int PERCENTAGE_INT = 100; + mTrailBodyRatio = (float)mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailBodyRatio, PERCENTAGE_INT) + / (float)PERCENTAGE_INT; + final int trailShadowRatioInt = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailShadowRatio, 0); + mTrailShadowEnabled = (trailShadowRatioInt > 0); + mTrailShadowRatio = (float)trailShadowRatioInt / (float)PERCENTAGE_INT; + mFadeoutStartDelay = DBG_SHOW_POINTS ? 2000 : mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailFadeoutStartDelay, 0); + mFadeoutDuration = DBG_SHOW_POINTS ? 200 : mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailFadeoutDuration, 0); + mTrailLingerDuration = mFadeoutStartDelay + mFadeoutDuration; + mUpdateInterval = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailUpdateInterval, 0); + } + } + + // Use this value as imaginary zero because x-coordinates may be zero. + private static final int DOWN_EVENT_MARKER = -128; + + private static int markAsDownEvent(final int xCoord) { + return DOWN_EVENT_MARKER - xCoord; + } + + private static boolean isDownEventXCoord(final int xCoordOrMark) { + return xCoordOrMark <= DOWN_EVENT_MARKER; + } + + private static int getXCoordValue(final int xCoordOrMark) { + return isDownEventXCoord(xCoordOrMark) + ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark; + } + + public void addStroke(final GestureStrokeWithPreviewPoints stroke, final long downTime) { + synchronized (mEventTimes) { + addStrokeLocked(stroke, downTime); + } + } + + private void addStrokeLocked(final GestureStrokeWithPreviewPoints stroke, final long downTime) { + final int trailSize = mEventTimes.getLength(); + stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates); + if (mEventTimes.getLength() == trailSize) { + return; + } + final int[] eventTimes = mEventTimes.getPrimitiveArray(); + final int strokeId = stroke.getGestureStrokeId(); + // Because interpolation algorithm in {@link GestureStrokeWithPreviewPoints} can't determine + // the interpolated points in the last segment of gesture stroke, it may need recalculation + // of interpolation when new segments are added to the stroke. + // {@link #mLastInterpolatedDrawIndex} holds the start index of the last segment. It may + // be updated by the interpolation + // {@link GestureStrokeWithPreviewPoints#interpolatePreviewStroke} + // or by animation {@link #drawGestureTrail(Canvas,Paint,Rect,Params)} below. + final int lastInterpolatedIndex = (strokeId == mCurrentStrokeId) + ? mLastInterpolatedDrawIndex : trailSize; + mLastInterpolatedDrawIndex = stroke.interpolateStrokeAndReturnStartIndexOfLastSegment( + lastInterpolatedIndex, mEventTimes, mXCoordinates, mYCoordinates, mPointTypes); + if (strokeId != mCurrentStrokeId) { + final int elapsedTime = (int)(downTime - mCurrentTimeBase); + for (int i = mTrailStartIndex; i < trailSize; i++) { + // Decay the previous strokes' event times. + eventTimes[i] -= elapsedTime; + } + final int[] xCoords = mXCoordinates.getPrimitiveArray(); + final int downIndex = trailSize; + xCoords[downIndex] = markAsDownEvent(xCoords[downIndex]); + mCurrentTimeBase = downTime - eventTimes[downIndex]; + mCurrentStrokeId = strokeId; + } + } + + /** + * Calculate the alpha of a gesture trail. + * A gesture trail starts from fully opaque. After mFadeStartDelay has been passed, the alpha + * of a trail reduces in proportion to the elapsed time. Then after mFadeDuration has been + * passed, a trail becomes fully transparent. + * + * @param elapsedTime the elapsed time since a trail has been made. + * @param params gesture trail display parameters + * @return the width of a gesture trail + */ + private static int getAlpha(final int elapsedTime, final Params params) { + if (elapsedTime < params.mFadeoutStartDelay) { + return Constants.Color.ALPHA_OPAQUE; + } + final int decreasingAlpha = Constants.Color.ALPHA_OPAQUE + * (elapsedTime - params.mFadeoutStartDelay) + / params.mFadeoutDuration; + return Constants.Color.ALPHA_OPAQUE - decreasingAlpha; + } + + /** + * Calculate the width of a gesture trail. + * A gesture trail starts from the width of mTrailStartWidth and reduces its width in proportion + * to the elapsed time. After mTrailEndWidth has been passed, the width becomes mTraiLEndWidth. + * + * @param elapsedTime the elapsed time since a trail has been made. + * @param params gesture trail display parameters + * @return the width of a gesture trail + */ + private static float getWidth(final int elapsedTime, final Params params) { + final float deltaWidth = params.mTrailStartWidth - params.mTrailEndWidth; + return params.mTrailStartWidth - (deltaWidth * elapsedTime) / params.mTrailLingerDuration; + } + + private final RoundedLine mRoundedLine = new RoundedLine(); + private final Rect mRoundedLineBounds = new Rect(); + + /** + * Draw gesture trail + * @param canvas The canvas to draw the gesture trail + * @param paint The paint object to be used to draw the gesture trail + * @param outBoundsRect the bounding box of this gesture trail drawing + * @param params The drawing parameters of gesture trail + * @return true if some gesture trails remain to be drawn + */ + public boolean drawGestureTrail(final Canvas canvas, final Paint paint, + final Rect outBoundsRect, final Params params) { + synchronized (mEventTimes) { + return drawGestureTrailLocked(canvas, paint, outBoundsRect, params); + } + } + + private boolean drawGestureTrailLocked(final Canvas canvas, final Paint paint, + final Rect outBoundsRect, final Params params) { + // Initialize bounds rectangle. + outBoundsRect.setEmpty(); + final int trailSize = mEventTimes.getLength(); + if (trailSize == 0) { + return false; + } + + final int[] eventTimes = mEventTimes.getPrimitiveArray(); + final int[] xCoords = mXCoordinates.getPrimitiveArray(); + final int[] yCoords = mYCoordinates.getPrimitiveArray(); + final int[] pointTypes = mPointTypes.getPrimitiveArray(); + final int sinceDown = (int)(SystemClock.uptimeMillis() - mCurrentTimeBase); + int startIndex; + for (startIndex = mTrailStartIndex; startIndex < trailSize; startIndex++) { + final int elapsedTime = sinceDown - eventTimes[startIndex]; + // Skip too old trail points. + if (elapsedTime < params.mTrailLingerDuration) { + break; + } + } + mTrailStartIndex = startIndex; + + if (startIndex < trailSize) { + paint.setColor(params.mTrailColor); + paint.setStyle(Paint.Style.FILL); + final RoundedLine roundedLine = mRoundedLine; + int p1x = getXCoordValue(xCoords[startIndex]); + int p1y = yCoords[startIndex]; + final int lastTime = sinceDown - eventTimes[startIndex]; + float r1 = getWidth(lastTime, params) / 2.0f; + for (int i = startIndex + 1; i < trailSize; i++) { + final int elapsedTime = sinceDown - eventTimes[i]; + final int p2x = getXCoordValue(xCoords[i]); + final int p2y = yCoords[i]; + final float r2 = getWidth(elapsedTime, params) / 2.0f; + // Draw trail line only when the current point isn't a down point. + if (!isDownEventXCoord(xCoords[i])) { + final float body1 = r1 * params.mTrailBodyRatio; + final float body2 = r2 * params.mTrailBodyRatio; + final Path path = roundedLine.makePath(p1x, p1y, body1, p2x, p2y, body2); + if (path != null) { + roundedLine.getBounds(mRoundedLineBounds); + if (params.mTrailShadowEnabled) { + final float shadow2 = r2 * params.mTrailShadowRatio; + paint.setShadowLayer(shadow2, 0.0f, 0.0f, params.mTrailColor); + final int shadowInset = -(int)Math.ceil(shadow2); + mRoundedLineBounds.inset(shadowInset, shadowInset); + } + // Take union for the bounds. + outBoundsRect.union(mRoundedLineBounds); + final int alpha = getAlpha(elapsedTime, params); + paint.setAlpha(alpha); + canvas.drawPath(path, paint); + if (DBG_SHOW_POINTS) { + if (pointTypes[i] == POINT_TYPE_INTERPOLATED) { + paint.setColor(Color.RED); + } else if (pointTypes[i] == POINT_TYPE_SAMPLED) { + paint.setColor(0xFFA000FF); + } else { + paint.setColor(Color.GREEN); + } + canvas.drawCircle(p1x - 1, p1y - 1, 2, paint); + paint.setColor(params.mTrailColor); + } + } + } + p1x = p2x; + p1y = p2y; + r1 = r2; + } + } + + final int newSize = trailSize - startIndex; + if (newSize < startIndex) { + mTrailStartIndex = 0; + if (newSize > 0) { + System.arraycopy(eventTimes, startIndex, eventTimes, 0, newSize); + System.arraycopy(xCoords, startIndex, xCoords, 0, newSize); + System.arraycopy(yCoords, startIndex, yCoords, 0, newSize); + } + mEventTimes.setLength(newSize); + mXCoordinates.setLength(newSize); + mYCoordinates.setLength(newSize); + if (DBG_SHOW_POINTS) { + mPointTypes.setLength(newSize); + } + // The start index of the last segment of the stroke + // {@link mLastInterpolatedDrawIndex} should also be updated because all array + // elements have just been shifted for compaction or been zeroed. + mLastInterpolatedDrawIndex = Math.max(mLastInterpolatedDrawIndex - startIndex, 0); + } + return newSize > 0; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java index 85558f1f6..1e4c43ee5 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java @@ -29,7 +29,7 @@ import android.util.SparseArray; import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; -import com.android.inputmethod.keyboard.internal.GesturePreviewTrail.Params; +import com.android.inputmethod.keyboard.internal.GestureTrail.Params; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; @@ -37,9 +37,8 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper; * Draw gesture trail preview graphics during gesture. */ public final class GestureTrailsPreview extends AbstractDrawingPreview { - private final SparseArray mGesturePreviewTrails = - CollectionUtils.newSparseArray(); - private final Params mGesturePreviewTrailParams; + private final SparseArray mGestureTrails = CollectionUtils.newSparseArray(); + private final Params mGestureTrailParams; private final Paint mGesturePaint; private int mOffscreenWidth; private int mOffscreenHeight; @@ -48,20 +47,20 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { private final Canvas mOffscreenCanvas = new Canvas(); private final Rect mOffscreenSrcRect = new Rect(); private final Rect mDirtyRect = new Rect(); - private final Rect mGesturePreviewTrailBoundsRect = new Rect(); // per trail + private final Rect mGestureTrailBoundsRect = new Rect(); // per trail private final DrawingHandler mDrawingHandler; private static final class DrawingHandler extends StaticInnerHandlerWrapper { - private static final int MSG_UPDATE_GESTURE_PREVIEW_TRAIL = 0; + private static final int MSG_UPDATE_GESTURE_TRAIL = 0; - private final Params mGesturePreviewTrailParams; + private final Params mGestureTrailParams; public DrawingHandler(final GestureTrailsPreview outerInstance, - final Params gesturePreviewTrailParams) { + final Params gestureTrailParams) { super(outerInstance); - mGesturePreviewTrailParams = gesturePreviewTrailParams; + mGestureTrailParams = gestureTrailParams; } @Override @@ -69,23 +68,23 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { final GestureTrailsPreview preview = getOuterInstance(); if (preview == null) return; switch (msg.what) { - case MSG_UPDATE_GESTURE_PREVIEW_TRAIL: + case MSG_UPDATE_GESTURE_TRAIL: preview.getDrawingView().invalidate(); break; } } public void postUpdateGestureTrailPreview() { - removeMessages(MSG_UPDATE_GESTURE_PREVIEW_TRAIL); - sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_TRAIL), - mGesturePreviewTrailParams.mUpdateInterval); + removeMessages(MSG_UPDATE_GESTURE_TRAIL); + sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_TRAIL), + mGestureTrailParams.mUpdateInterval); } } public GestureTrailsPreview(final View drawingView, final TypedArray mainKeyboardViewAttr) { super(drawingView); - mGesturePreviewTrailParams = new Params(mainKeyboardViewAttr); - mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams); + mGestureTrailParams = new Params(mainKeyboardViewAttr); + mDrawingHandler = new DrawingHandler(this, mGestureTrailParams); final Paint gesturePaint = new Paint(); gesturePaint.setAntiAlias(true); gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); @@ -133,21 +132,20 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { offscreenCanvas.drawRect(dirtyRect, paint); } dirtyRect.setEmpty(); - boolean needsUpdatingGesturePreviewTrail = false; + boolean needsUpdatingGestureTrail = false; // Draw gesture trails to offscreen buffer. - synchronized (mGesturePreviewTrails) { + synchronized (mGestureTrails) { // Trails count == fingers count that have ever been active. - final int trailsCount = mGesturePreviewTrails.size(); + final int trailsCount = mGestureTrails.size(); for (int index = 0; index < trailsCount; index++) { - final GesturePreviewTrail trail = mGesturePreviewTrails.valueAt(index); - needsUpdatingGesturePreviewTrail |= - trail.drawGestureTrail(offscreenCanvas, paint, - mGesturePreviewTrailBoundsRect, mGesturePreviewTrailParams); - // {@link #mGesturePreviewTrailBoundsRect} has bounding box of the trail. - dirtyRect.union(mGesturePreviewTrailBoundsRect); + final GestureTrail trail = mGestureTrails.valueAt(index); + needsUpdatingGestureTrail |= trail.drawGestureTrail(offscreenCanvas, paint, + mGestureTrailBoundsRect, mGestureTrailParams); + // {@link #mGestureTrailBoundsRect} has bounding box of the trail. + dirtyRect.union(mGestureTrailBoundsRect); } } - return needsUpdatingGesturePreviewTrail; + return needsUpdatingGestureTrail; } /** @@ -161,9 +159,9 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { } mayAllocateOffscreenBuffer(); // Draw gesture trails to offscreen buffer. - final boolean needsUpdatingGesturePreviewTrail = drawGestureTrails( + final boolean needsUpdatingGestureTrail = drawGestureTrails( mOffscreenCanvas, mGesturePaint, mDirtyRect); - if (needsUpdatingGesturePreviewTrail) { + if (needsUpdatingGestureTrail) { mDrawingHandler.postUpdateGestureTrailPreview(); } // Transfer offscreen buffer to screen. @@ -185,12 +183,12 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { if (!isPreviewEnabled()) { return; } - GesturePreviewTrail trail; - synchronized (mGesturePreviewTrails) { - trail = mGesturePreviewTrails.get(tracker.mPointerId); + GestureTrail trail; + synchronized (mGestureTrails) { + trail = mGestureTrails.get(tracker.mPointerId); if (trail == null) { - trail = new GesturePreviewTrail(); - mGesturePreviewTrails.put(tracker.mPointerId, trail); + trail = new GestureTrail(); + mGestureTrails.put(tracker.mPointerId, trail); } } trail.addStroke(tracker.getGestureStrokeWithPreviewPoints(), tracker.getDownTime()); -- cgit v1.2.3-83-g751a