Add multiple gesture preview trails animation
Change-Id: I533e6de9b138317472565be82c8ba5e422472888main
parent
64a26b4389
commit
333a300586
|
@ -131,6 +131,12 @@
|
||||||
<attr name="gestureFloatingPreviewTextConnectorWidth" format="dimension" />
|
<attr name="gestureFloatingPreviewTextConnectorWidth" format="dimension" />
|
||||||
<!-- Delay after gesture input and gesture floating preview text dismissing in millisecond -->
|
<!-- Delay after gesture input and gesture floating preview text dismissing in millisecond -->
|
||||||
<attr name="gestureFloatingPreviewTextLingerTimeout" format="integer" />
|
<attr name="gestureFloatingPreviewTextLingerTimeout" format="integer" />
|
||||||
|
<!-- Delay after gesture trail starts fading out in millisecond. -->
|
||||||
|
<attr name="gesturePreviewTrailFadeoutStartDelay" format="integer" />
|
||||||
|
<!-- Duration while gesture preview trail is fading out in millisecond. -->
|
||||||
|
<attr name="gesturePreviewTrailFadeoutDuration" format="integer" />
|
||||||
|
<!-- Interval of updating gesture preview trail in millisecond. -->
|
||||||
|
<attr name="gesturePreviewTrailUpdateInterval" format="integer" />
|
||||||
<attr name="gesturePreviewTrailColor" format="color" />
|
<attr name="gesturePreviewTrailColor" format="color" />
|
||||||
<attr name="gesturePreviewTrailWidth" format="dimension" />
|
<attr name="gesturePreviewTrailWidth" format="dimension" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
|
@ -50,6 +50,9 @@
|
||||||
-->
|
-->
|
||||||
<integer name="config_key_preview_linger_timeout">70</integer>
|
<integer name="config_key_preview_linger_timeout">70</integer>
|
||||||
<integer name="config_gesture_floating_preview_text_linger_timeout">200</integer>
|
<integer name="config_gesture_floating_preview_text_linger_timeout">200</integer>
|
||||||
|
<integer name="config_gesture_preview_trail_fadeout_start_delay">100</integer>
|
||||||
|
<integer name="config_gesture_preview_trail_fadeout_duration">1000</integer>
|
||||||
|
<integer name="config_gesture_preview_trail_update_interval">20</integer>
|
||||||
<!--
|
<!--
|
||||||
Configuration for MainKeyboardView
|
Configuration for MainKeyboardView
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -78,6 +78,9 @@
|
||||||
<item name="gestureFloatingPreviewTextConnectorColor">@android:color/white</item>
|
<item name="gestureFloatingPreviewTextConnectorColor">@android:color/white</item>
|
||||||
<item name="gestureFloatingPreviewTextConnectorWidth">@dimen/gesture_floating_preview_text_connector_width</item>
|
<item name="gestureFloatingPreviewTextConnectorWidth">@dimen/gesture_floating_preview_text_connector_width</item>
|
||||||
<item name="gestureFloatingPreviewTextLingerTimeout">@integer/config_gesture_floating_preview_text_linger_timeout</item>
|
<item name="gestureFloatingPreviewTextLingerTimeout">@integer/config_gesture_floating_preview_text_linger_timeout</item>
|
||||||
|
<item name="gesturePreviewTrailFadeoutStartDelay">@integer/config_gesture_preview_trail_fadeout_start_delay</item>
|
||||||
|
<item name="gesturePreviewTrailFadeoutDuration">@integer/config_gesture_preview_trail_fadeout_duration</item>
|
||||||
|
<item name="gesturePreviewTrailUpdateInterval">@integer/config_gesture_preview_trail_update_interval</item>
|
||||||
<item name="gesturePreviewTrailColor">@android:color/holo_blue_light</item>
|
<item name="gesturePreviewTrailColor">@android:color/holo_blue_light</item>
|
||||||
<item name="gesturePreviewTrailWidth">@dimen/gesture_preview_trail_width</item>
|
<item name="gesturePreviewTrailWidth">@dimen/gesture_preview_trail_width</item>
|
||||||
<!-- Common attributes of MainKeyboardView -->
|
<!-- Common attributes of MainKeyboardView -->
|
||||||
|
|
|
@ -17,14 +17,13 @@
|
||||||
package com.android.inputmethod.keyboard;
|
package com.android.inputmethod.keyboard;
|
||||||
|
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
||||||
import com.android.inputmethod.keyboard.internal.GestureStroke;
|
import com.android.inputmethod.keyboard.internal.GestureStroke;
|
||||||
|
import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewTrail;
|
||||||
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
|
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
|
||||||
import com.android.inputmethod.latin.CollectionUtils;
|
import com.android.inputmethod.latin.CollectionUtils;
|
||||||
import com.android.inputmethod.latin.InputPointers;
|
import com.android.inputmethod.latin.InputPointers;
|
||||||
|
@ -211,7 +210,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
private static final KeyboardActionListener EMPTY_LISTENER =
|
private static final KeyboardActionListener EMPTY_LISTENER =
|
||||||
new KeyboardActionListener.Adapter();
|
new KeyboardActionListener.Adapter();
|
||||||
|
|
||||||
private final GestureStroke mGestureStroke;
|
private final GestureStrokeWithPreviewTrail mGestureStrokeWithPreviewTrail;
|
||||||
|
|
||||||
public static void init(boolean hasDistinctMultitouch,
|
public static void init(boolean hasDistinctMultitouch,
|
||||||
boolean needsPhantomSuddenMoveEventHack) {
|
boolean needsPhantomSuddenMoveEventHack) {
|
||||||
|
@ -297,7 +296,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
final int trackersSize = sTrackers.size();
|
final int trackersSize = sTrackers.size();
|
||||||
for (int i = 0; i < trackersSize; ++i) {
|
for (int i = 0; i < trackersSize; ++i) {
|
||||||
final PointerTracker tracker = sTrackers.get(i);
|
final PointerTracker tracker = sTrackers.get(i);
|
||||||
tracker.mGestureStroke.appendIncrementalBatchPoints(sAggregratedPointers);
|
tracker.mGestureStrokeWithPreviewTrail.appendIncrementalBatchPoints(
|
||||||
|
sAggregratedPointers);
|
||||||
}
|
}
|
||||||
return sAggregratedPointers;
|
return sAggregratedPointers;
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
final int trackersSize = sTrackers.size();
|
final int trackersSize = sTrackers.size();
|
||||||
for (int i = 0; i < trackersSize; ++i) {
|
for (int i = 0; i < trackersSize; ++i) {
|
||||||
final PointerTracker tracker = sTrackers.get(i);
|
final PointerTracker tracker = sTrackers.get(i);
|
||||||
tracker.mGestureStroke.appendAllBatchPoints(sAggregratedPointers);
|
tracker.mGestureStrokeWithPreviewTrail.appendAllBatchPoints(sAggregratedPointers);
|
||||||
}
|
}
|
||||||
return sAggregratedPointers;
|
return sAggregratedPointers;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
final int trackersSize = sTrackers.size();
|
final int trackersSize = sTrackers.size();
|
||||||
for (int i = 0; i < trackersSize; ++i) {
|
for (int i = 0; i < trackersSize; ++i) {
|
||||||
final PointerTracker tracker = sTrackers.get(i);
|
final PointerTracker tracker = sTrackers.get(i);
|
||||||
tracker.mGestureStroke.reset();
|
tracker.mGestureStrokeWithPreviewTrail.reset();
|
||||||
}
|
}
|
||||||
sAggregratedPointers.reset();
|
sAggregratedPointers.reset();
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
}
|
}
|
||||||
mPointerId = id;
|
mPointerId = id;
|
||||||
mGestureStroke = new GestureStroke(id);
|
mGestureStrokeWithPreviewTrail = new GestureStrokeWithPreviewTrail(id);
|
||||||
setKeyDetectorInner(handler.getKeyDetector());
|
setKeyDetectorInner(handler.getKeyDetector());
|
||||||
mListener = handler.getKeyboardActionListener();
|
mListener = handler.getKeyboardActionListener();
|
||||||
mDrawingProxy = handler.getDrawingProxy();
|
mDrawingProxy = handler.getDrawingProxy();
|
||||||
|
@ -429,7 +429,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
mKeyDetector = keyDetector;
|
mKeyDetector = keyDetector;
|
||||||
mKeyboard = keyDetector.getKeyboard();
|
mKeyboard = keyDetector.getKeyboard();
|
||||||
mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard();
|
mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard();
|
||||||
mGestureStroke.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth);
|
mGestureStrokeWithPreviewTrail.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth);
|
||||||
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
|
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
|
||||||
if (newKey != mCurrentKey) {
|
if (newKey != mCurrentKey) {
|
||||||
if (mDrawingProxy != null) {
|
if (mDrawingProxy != null) {
|
||||||
|
@ -539,10 +539,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
mDrawingProxy.invalidateKey(key);
|
mDrawingProxy.invalidateKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawGestureTrail(final Canvas canvas, final Paint paint) {
|
public GestureStrokeWithPreviewTrail getGestureStrokeWithPreviewTrail() {
|
||||||
if (mInGesture) {
|
return mGestureStrokeWithPreviewTrail;
|
||||||
mGestureStroke.drawGestureTrail(canvas, paint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLastX() {
|
public int getLastX() {
|
||||||
|
@ -692,7 +690,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
mIsPossibleGesture = true;
|
mIsPossibleGesture = true;
|
||||||
// TODO: pointer times should be relative to first down even in entire batch input
|
// TODO: pointer times should be relative to first down even in entire batch input
|
||||||
// instead of resetting to 0 for each new down event.
|
// instead of resetting to 0 for each new down event.
|
||||||
mGestureStroke.addPoint(x, y, 0, false);
|
mGestureStrokeWithPreviewTrail.addPoint(x, y, 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -733,7 +731,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
final long eventTime, final boolean isHistorical, final Key key) {
|
final long eventTime, final boolean isHistorical, final Key key) {
|
||||||
final int gestureTime = (int)(eventTime - tracker.getDownTime());
|
final int gestureTime = (int)(eventTime - tracker.getDownTime());
|
||||||
if (sShouldHandleGesture && mIsPossibleGesture) {
|
if (sShouldHandleGesture && mIsPossibleGesture) {
|
||||||
final GestureStroke stroke = mGestureStroke;
|
final GestureStroke stroke = mGestureStrokeWithPreviewTrail;
|
||||||
stroke.addPoint(x, y, gestureTime, isHistorical);
|
stroke.addPoint(x, y, gestureTime, isHistorical);
|
||||||
if (!mInGesture && stroke.isStartOfAGesture()) {
|
if (!mInGesture && stroke.isStartOfAGesture()) {
|
||||||
startBatchInput();
|
startBatchInput();
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
* 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.Paint;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import com.android.inputmethod.latin.Constants;
|
||||||
|
import com.android.inputmethod.latin.R;
|
||||||
|
import com.android.inputmethod.latin.ResizableIntArray;
|
||||||
|
|
||||||
|
class GesturePreviewTrail {
|
||||||
|
private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewTrail.PREVIEW_CAPACITY;
|
||||||
|
|
||||||
|
private final GesturePreviewTrailParams mPreviewParams;
|
||||||
|
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 int mCurrentStrokeId;
|
||||||
|
private long mCurrentDownTime;
|
||||||
|
|
||||||
|
// Use this value as imaginary zero because x-coordinates may be zero.
|
||||||
|
private static final int DOWN_EVENT_MARKER = -128;
|
||||||
|
|
||||||
|
static class GesturePreviewTrailParams {
|
||||||
|
public final int mFadeoutStartDelay;
|
||||||
|
public final int mFadeoutDuration;
|
||||||
|
public final int mUpdateInterval;
|
||||||
|
|
||||||
|
public GesturePreviewTrailParams(final TypedArray keyboardViewAttr) {
|
||||||
|
mFadeoutStartDelay = keyboardViewAttr.getInt(
|
||||||
|
R.styleable.KeyboardView_gesturePreviewTrailFadeoutStartDelay, 0);
|
||||||
|
mFadeoutDuration = keyboardViewAttr.getInt(
|
||||||
|
R.styleable.KeyboardView_gesturePreviewTrailFadeoutDuration, 0);
|
||||||
|
mUpdateInterval = keyboardViewAttr.getInt(
|
||||||
|
R.styleable.KeyboardView_gesturePreviewTrailUpdateInterval, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GesturePreviewTrail(final GesturePreviewTrailParams params) {
|
||||||
|
mPreviewParams = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 GestureStrokeWithPreviewTrail stroke, final long downTime) {
|
||||||
|
final int strokeId = stroke.getGestureStrokeId();
|
||||||
|
final boolean isNewStroke = strokeId != mCurrentStrokeId;
|
||||||
|
final int trailSize = mEventTimes.getLength();
|
||||||
|
stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates);
|
||||||
|
final int newTrailSize = mEventTimes.getLength();
|
||||||
|
if (stroke.getGestureStrokePreviewSize() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNewStroke) {
|
||||||
|
final int elapsedTime = (int)(downTime - mCurrentDownTime);
|
||||||
|
final int[] eventTimes = mEventTimes.getPrimitiveArray();
|
||||||
|
for (int i = 0; i < trailSize; i++) {
|
||||||
|
eventTimes[i] -= elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newTrailSize > trailSize) {
|
||||||
|
final int[] xCoords = mXCoordinates.getPrimitiveArray();
|
||||||
|
xCoords[trailSize] = markAsDownEvent(xCoords[trailSize]);
|
||||||
|
}
|
||||||
|
mCurrentDownTime = downTime;
|
||||||
|
mCurrentStrokeId = strokeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getAlpha(final int elapsedTime) {
|
||||||
|
if (elapsedTime < mPreviewParams.mFadeoutStartDelay) {
|
||||||
|
return Constants.Color.ALPHA_OPAQUE;
|
||||||
|
}
|
||||||
|
final int decreasingAlpha = Constants.Color.ALPHA_OPAQUE
|
||||||
|
* (elapsedTime - mPreviewParams.mFadeoutStartDelay)
|
||||||
|
/ mPreviewParams.mFadeoutDuration;
|
||||||
|
return Constants.Color.ALPHA_OPAQUE - decreasingAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @return true if some gesture preview trails remain to be drawn
|
||||||
|
*/
|
||||||
|
public boolean drawGestureTrail(final Canvas canvas, final Paint paint) {
|
||||||
|
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 sinceDown = (int)(SystemClock.uptimeMillis() - mCurrentDownTime);
|
||||||
|
final int lingeringDuration = mPreviewParams.mFadeoutStartDelay
|
||||||
|
+ mPreviewParams.mFadeoutDuration;
|
||||||
|
int startIndex;
|
||||||
|
for (startIndex = 0; startIndex < trailSize; startIndex++) {
|
||||||
|
final int elapsedTime = sinceDown - eventTimes[startIndex];
|
||||||
|
// Skip too old trail points.
|
||||||
|
if (elapsedTime < lingeringDuration) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startIndex < trailSize) {
|
||||||
|
int lastX = getXCoordValue(xCoords[startIndex]);
|
||||||
|
int lastY = yCoords[startIndex];
|
||||||
|
for (int i = startIndex + 1; i < trailSize - 1; i++) {
|
||||||
|
final int x = xCoords[i];
|
||||||
|
final int y = yCoords[i];
|
||||||
|
final int elapsedTime = sinceDown - eventTimes[i];
|
||||||
|
// Draw trail line only when the current point isn't a down point.
|
||||||
|
if (!isDownEventXCoord(x)) {
|
||||||
|
paint.setAlpha(getAlpha(elapsedTime));
|
||||||
|
canvas.drawLine(lastX, lastY, x, y, paint);
|
||||||
|
}
|
||||||
|
lastX = getXCoordValue(x);
|
||||||
|
lastY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement ring buffer to avoid moving points.
|
||||||
|
// Discard faded out points.
|
||||||
|
final int newSize = trailSize - startIndex;
|
||||||
|
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);
|
||||||
|
return newSize > 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,6 @@
|
||||||
|
|
||||||
package com.android.inputmethod.keyboard.internal;
|
package com.android.inputmethod.keyboard.internal;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.Constants;
|
|
||||||
import com.android.inputmethod.latin.InputPointers;
|
import com.android.inputmethod.latin.InputPointers;
|
||||||
import com.android.inputmethod.latin.ResizableIntArray;
|
import com.android.inputmethod.latin.ResizableIntArray;
|
||||||
|
|
||||||
|
@ -48,13 +44,8 @@ public class GestureStroke {
|
||||||
|
|
||||||
private static final float DOUBLE_PI = (float)(2.0f * Math.PI);
|
private static final float DOUBLE_PI = (float)(2.0f * Math.PI);
|
||||||
|
|
||||||
// Fade based on number of gesture samples, see MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT
|
public GestureStroke(final int pointerId) {
|
||||||
private static final int DRAWING_GESTURE_FADE_START = 10;
|
|
||||||
private static final int DRAWING_GESTURE_FADE_RATE = 6;
|
|
||||||
|
|
||||||
public GestureStroke(int pointerId) {
|
|
||||||
mPointerId = pointerId;
|
mPointerId = pointerId;
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGestureSampleLength(final int keyWidth) {
|
public void setGestureSampleLength(final int keyWidth) {
|
||||||
|
@ -158,7 +149,7 @@ public class GestureStroke {
|
||||||
if (dx == 0 && dy == 0) return 0;
|
if (dx == 0 && dy == 0) return 0;
|
||||||
// Would it be faster to call atan2f() directly via JNI? Not sure about what the JIT
|
// Would it be faster to call atan2f() directly via JNI? Not sure about what the JIT
|
||||||
// does with Math.atan2().
|
// does with Math.atan2().
|
||||||
return (float)Math.atan2((double)dy, (double)dx);
|
return (float)Math.atan2(dy, dx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float getAngleDiff(final float a1, final float a2) {
|
private static float getAngleDiff(final float a1, final float a2) {
|
||||||
|
@ -168,20 +159,4 @@ public class GestureStroke {
|
||||||
}
|
}
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawGestureTrail(final Canvas canvas, final Paint paint) {
|
|
||||||
// TODO: These paint parameter interpolation should be tunable, possibly introduce an object
|
|
||||||
// that implements an interface such as Paint getPaint(int step, int strokePoints)
|
|
||||||
final int size = mXCoordinates.getLength();
|
|
||||||
final int[] xCoords = mXCoordinates.getPrimitiveArray();
|
|
||||||
final int[] yCoords = mYCoordinates.getPrimitiveArray();
|
|
||||||
int alpha = Constants.Color.ALPHA_OPAQUE;
|
|
||||||
for (int i = size - 1; i > 0 && alpha > 0; i--) {
|
|
||||||
paint.setAlpha(alpha);
|
|
||||||
if (size - i > DRAWING_GESTURE_FADE_START) {
|
|
||||||
alpha -= DRAWING_GESTURE_FADE_RATE;
|
|
||||||
}
|
|
||||||
canvas.drawLine(xCoords[i - 1], yCoords[i - 1], xCoords[i], yCoords[i], paint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* 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 com.android.inputmethod.latin.ResizableIntArray;
|
||||||
|
|
||||||
|
public class GestureStrokeWithPreviewTrail extends GestureStroke {
|
||||||
|
public static final int PREVIEW_CAPACITY = 256;
|
||||||
|
|
||||||
|
private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY);
|
||||||
|
private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
|
||||||
|
private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
|
||||||
|
|
||||||
|
private int mStrokeId;
|
||||||
|
private int mLastPreviewSize;
|
||||||
|
|
||||||
|
public GestureStrokeWithPreviewTrail(final int pointerId) {
|
||||||
|
super(pointerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
super.reset();
|
||||||
|
mStrokeId++;
|
||||||
|
mLastPreviewSize = 0;
|
||||||
|
mPreviewEventTimes.setLength(0);
|
||||||
|
mPreviewXCoordinates.setLength(0);
|
||||||
|
mPreviewYCoordinates.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGestureStrokeId() {
|
||||||
|
return mStrokeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGestureStrokePreviewSize() {
|
||||||
|
return mPreviewEventTimes.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addPoint(final int x, final int y, final int time, final boolean isHistorical) {
|
||||||
|
super.addPoint(x, y, time, isHistorical);
|
||||||
|
mPreviewEventTimes.add(time);
|
||||||
|
mPreviewXCoordinates.add(x);
|
||||||
|
mPreviewYCoordinates.add(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendPreviewStroke(final ResizableIntArray eventTimes,
|
||||||
|
final ResizableIntArray xCoords, final ResizableIntArray yCoords) {
|
||||||
|
final int length = mPreviewEventTimes.getLength() - mLastPreviewSize;
|
||||||
|
if (length <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventTimes.append(mPreviewEventTimes, mLastPreviewSize, length);
|
||||||
|
xCoords.append(mPreviewXCoordinates, mLastPreviewSize, length);
|
||||||
|
yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length);
|
||||||
|
mLastPreviewSize = mPreviewEventTimes.getLength();
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import android.util.SparseArray;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.PointerTracker;
|
import com.android.inputmethod.keyboard.PointerTracker;
|
||||||
|
import com.android.inputmethod.keyboard.internal.GesturePreviewTrail.GesturePreviewTrailParams;
|
||||||
import com.android.inputmethod.latin.CollectionUtils;
|
import com.android.inputmethod.latin.CollectionUtils;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
||||||
|
@ -48,7 +49,9 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
private int mXOrigin;
|
private int mXOrigin;
|
||||||
private int mYOrigin;
|
private int mYOrigin;
|
||||||
|
|
||||||
private final SparseArray<PointerTracker> mPointers = CollectionUtils.newSparseArray();
|
private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails =
|
||||||
|
CollectionUtils.newSparseArray();
|
||||||
|
private final GesturePreviewTrailParams mGesturePreviewTrailParams;
|
||||||
|
|
||||||
private String mGestureFloatingPreviewText;
|
private String mGestureFloatingPreviewText;
|
||||||
private int mLastPointerX;
|
private int mLastPointerX;
|
||||||
|
@ -57,23 +60,31 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
private boolean mDrawsGesturePreviewTrail;
|
private boolean mDrawsGesturePreviewTrail;
|
||||||
private boolean mDrawsGestureFloatingPreviewText;
|
private boolean mDrawsGestureFloatingPreviewText;
|
||||||
|
|
||||||
private final DrawingHandler mDrawingHandler = new DrawingHandler(this);
|
private final DrawingHandler mDrawingHandler;
|
||||||
|
|
||||||
private static class DrawingHandler extends StaticInnerHandlerWrapper<PreviewPlacerView> {
|
private static class DrawingHandler extends StaticInnerHandlerWrapper<PreviewPlacerView> {
|
||||||
private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 0;
|
private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 0;
|
||||||
|
private static final int MSG_UPDATE_GESTURE_PREVIEW_TRAIL = 1;
|
||||||
|
|
||||||
public DrawingHandler(PreviewPlacerView outerInstance) {
|
private final GesturePreviewTrailParams mGesturePreviewTrailParams;
|
||||||
|
|
||||||
|
public DrawingHandler(final PreviewPlacerView outerInstance,
|
||||||
|
final GesturePreviewTrailParams gesturePreviewTrailParams) {
|
||||||
super(outerInstance);
|
super(outerInstance);
|
||||||
|
mGesturePreviewTrailParams = gesturePreviewTrailParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(final Message msg) {
|
||||||
final PreviewPlacerView placerView = getOuterInstance();
|
final PreviewPlacerView placerView = getOuterInstance();
|
||||||
if (placerView == null) return;
|
if (placerView == null) return;
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT:
|
case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT:
|
||||||
placerView.setGestureFloatingPreviewText(null);
|
placerView.setGestureFloatingPreviewText(null);
|
||||||
break;
|
break;
|
||||||
|
case MSG_UPDATE_GESTURE_PREVIEW_TRAIL:
|
||||||
|
placerView.invalidate();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,16 +100,27 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
placerView.mGestureFloatingPreviewTextLingerTimeout);
|
placerView.mGestureFloatingPreviewTextLingerTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cancelUpdateGestureTrailPreview() {
|
||||||
|
removeMessages(MSG_UPDATE_GESTURE_PREVIEW_TRAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postUpdateGestureTrailPreview() {
|
||||||
|
cancelUpdateGestureTrailPreview();
|
||||||
|
sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_TRAIL),
|
||||||
|
mGesturePreviewTrailParams.mUpdateInterval);
|
||||||
|
}
|
||||||
|
|
||||||
public void cancelAllMessages() {
|
public void cancelAllMessages() {
|
||||||
cancelDismissGestureFloatingPreviewText();
|
cancelDismissGestureFloatingPreviewText();
|
||||||
|
cancelUpdateGestureTrailPreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PreviewPlacerView(Context context, AttributeSet attrs) {
|
public PreviewPlacerView(final Context context, final AttributeSet attrs) {
|
||||||
this(context, attrs, R.attr.keyboardViewStyle);
|
this(context, attrs, R.attr.keyboardViewStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PreviewPlacerView(Context context, AttributeSet attrs, int defStyle) {
|
public PreviewPlacerView(final Context context, final AttributeSet attrs, final int defStyle) {
|
||||||
super(context);
|
super(context);
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
|
|
||||||
|
@ -128,8 +150,11 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
R.styleable.KeyboardView_gesturePreviewTrailColor, 0);
|
R.styleable.KeyboardView_gesturePreviewTrailColor, 0);
|
||||||
final int gesturePreviewTrailWidth = keyboardViewAttr.getDimensionPixelSize(
|
final int gesturePreviewTrailWidth = keyboardViewAttr.getDimensionPixelSize(
|
||||||
R.styleable.KeyboardView_gesturePreviewTrailWidth, 0);
|
R.styleable.KeyboardView_gesturePreviewTrailWidth, 0);
|
||||||
|
mGesturePreviewTrailParams = new GesturePreviewTrailParams(keyboardViewAttr);
|
||||||
keyboardViewAttr.recycle();
|
keyboardViewAttr.recycle();
|
||||||
|
|
||||||
|
mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams);
|
||||||
|
|
||||||
mGesturePaint = new Paint();
|
mGesturePaint = new Paint();
|
||||||
mGesturePaint.setAntiAlias(true);
|
mGesturePaint.setAntiAlias(true);
|
||||||
mGesturePaint.setStyle(Paint.Style.STROKE);
|
mGesturePaint.setStyle(Paint.Style.STROKE);
|
||||||
|
@ -144,21 +169,28 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
mTextPaint.setTextSize(gestureFloatingPreviewTextSize);
|
mTextPaint.setTextSize(gestureFloatingPreviewTextSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrigin(int x, int y) {
|
public void setOrigin(final int x, final int y) {
|
||||||
mXOrigin = x;
|
mXOrigin = x;
|
||||||
mYOrigin = y;
|
mYOrigin = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGesturePreviewMode(boolean drawsGesturePreviewTrail,
|
public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail,
|
||||||
boolean drawsGestureFloatingPreviewText) {
|
final boolean drawsGestureFloatingPreviewText) {
|
||||||
mDrawsGesturePreviewTrail = drawsGesturePreviewTrail;
|
mDrawsGesturePreviewTrail = drawsGesturePreviewTrail;
|
||||||
mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText;
|
mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidatePointer(PointerTracker tracker) {
|
public void invalidatePointer(final PointerTracker tracker) {
|
||||||
synchronized (mPointers) {
|
GesturePreviewTrail trail;
|
||||||
mPointers.put(tracker.mPointerId, tracker);
|
synchronized (mGesturePreviewTrails) {
|
||||||
|
trail = mGesturePreviewTrails.get(tracker.mPointerId);
|
||||||
|
if (trail == null) {
|
||||||
|
trail = new GesturePreviewTrail(mGesturePreviewTrailParams);
|
||||||
|
mGesturePreviewTrails.put(tracker.mPointerId, trail);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
trail.addStroke(tracker.getGestureStrokeWithPreviewTrail(), tracker.getDownTime());
|
||||||
|
|
||||||
mLastPointerX = tracker.getLastX();
|
mLastPointerX = tracker.getLastX();
|
||||||
mLastPointerY = tracker.getLastY();
|
mLastPointerY = tracker.getLastY();
|
||||||
// TODO: Should narrow the invalidate region.
|
// TODO: Should narrow the invalidate region.
|
||||||
|
@ -166,17 +198,23 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas canvas) {
|
public void onDraw(final Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
canvas.translate(mXOrigin, mYOrigin);
|
canvas.translate(mXOrigin, mYOrigin);
|
||||||
if (mDrawsGesturePreviewTrail) {
|
if (mDrawsGesturePreviewTrail) {
|
||||||
synchronized (mPointers) {
|
boolean needsUpdatingGesturePreviewTrail = false;
|
||||||
final int trackerCount = mPointers.size();
|
synchronized (mGesturePreviewTrails) {
|
||||||
for (int index = 0; index < trackerCount; index++) {
|
// Trails count == fingers count that have ever been active.
|
||||||
final PointerTracker tracker = mPointers.valueAt(index);
|
final int trailsCount = mGesturePreviewTrails.size();
|
||||||
tracker.drawGestureTrail(canvas, mGesturePaint);
|
for (int index = 0; index < trailsCount; index++) {
|
||||||
|
final GesturePreviewTrail trail = mGesturePreviewTrails.valueAt(index);
|
||||||
|
needsUpdatingGesturePreviewTrail |=
|
||||||
|
trail.drawGestureTrail(canvas, mGesturePaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (needsUpdatingGesturePreviewTrail) {
|
||||||
|
mDrawingHandler.postUpdateGestureTrailPreview();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mDrawsGestureFloatingPreviewText) {
|
if (mDrawsGestureFloatingPreviewText) {
|
||||||
drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
|
drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
|
||||||
|
@ -184,7 +222,7 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
canvas.translate(-mXOrigin, -mYOrigin);
|
canvas.translate(-mXOrigin, -mYOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGestureFloatingPreviewText(String gestureFloatingPreviewText) {
|
public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
|
||||||
mGestureFloatingPreviewText = gestureFloatingPreviewText;
|
mGestureFloatingPreviewText = gestureFloatingPreviewText;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
@ -197,7 +235,8 @@ public class PreviewPlacerView extends RelativeLayout {
|
||||||
mDrawingHandler.cancelAllMessages();
|
mDrawingHandler.cancelAllMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawGestureFloatingPreviewText(Canvas canvas, String gestureFloatingPreviewText) {
|
private void drawGestureFloatingPreviewText(final Canvas canvas,
|
||||||
|
final String gestureFloatingPreviewText) {
|
||||||
if (TextUtils.isEmpty(gestureFloatingPreviewText)) {
|
if (TextUtils.isEmpty(gestureFloatingPreviewText)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue