Loading java/src/com/android/inputmethod/keyboard/KeyboardView.java +62 −7 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.view.ViewGroup; import android.widget.RelativeLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.TextView; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; Loading Loading @@ -94,7 +95,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // The maximum key label width in the proportion to the key width. // The maximum key label width in the proportion to the key width. private static final float MAX_LABEL_RATIO = 0.90f; private static final float MAX_LABEL_RATIO = 0.90f; public final static int ALPHA_OPAQUE = 255; private final static int GESTURE_DRAWING_WIDTH = 5; private final static int GESTURE_DRAWING_COLOR = 0xff33b5e5; // Main keyboard // Main keyboard private Keyboard mKeyboard; private Keyboard mKeyboard; Loading @@ -118,11 +120,14 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final HashSet<Key> mInvalidatedKeys = new HashSet<Key>(); private final HashSet<Key> mInvalidatedKeys = new HashSet<Key>(); /** The region of invalidated keys */ /** The region of invalidated keys */ private final Rect mInvalidatedKeysRect = new Rect(); private final Rect mInvalidatedKeysRect = new Rect(); /** The region of invalidated gestures */ private final Rect mInvalidatedGesturesRect = new Rect(); /** The keyboard bitmap buffer for faster updates */ /** The keyboard bitmap buffer for faster updates */ private Bitmap mBuffer; private Bitmap mBuffer; /** The canvas for the above mutable keyboard bitmap */ /** The canvas for the above mutable keyboard bitmap */ private Canvas mCanvas; private Canvas mCanvas; private final Paint mPaint = new Paint(); private final Paint mPaint = new Paint(); private final Paint mGesturePaint = new Paint(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); // This sparse array caches key label text height in pixel indexed by key label text size. // This sparse array caches key label text height in pixel indexed by key label text size. private static final SparseArray<Float> sTextHeightCache = new SparseArray<Float>(); private static final SparseArray<Float> sTextHeightCache = new SparseArray<Float>(); Loading Loading @@ -264,7 +269,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public void blendAlpha(Paint paint) { public void blendAlpha(Paint paint) { final int color = paint.getColor(); final int color = paint.getColor(); paint.setARGB((paint.getAlpha() * mAnimAlpha) / ALPHA_OPAQUE, paint.setARGB((paint.getAlpha() * mAnimAlpha) / Constants.Color.ALPHA_OPAQUE, Color.red(color), Color.green(color), Color.blue(color)); Color.red(color), Color.green(color), Color.blue(color)); } } } } Loading Loading @@ -372,6 +377,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mPaint.setAntiAlias(true); mPaint.setAntiAlias(true); // TODO: These paint parameters should be specified via attribute of the view and styleable. mGesturePaint.setAntiAlias(true); mGesturePaint.setStyle(Paint.Style.STROKE); mGesturePaint.setStrokeJoin(Paint.Join.ROUND); mGesturePaint.setColor(GESTURE_DRAWING_COLOR); mGesturePaint.setStrokeWidth(GESTURE_DRAWING_WIDTH); } } // Read fraction value in TypedArray as float. // Read fraction value in TypedArray as float. Loading Loading @@ -517,7 +529,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final int keyDrawY = key.mY + getPaddingTop(); final int keyDrawY = key.mY + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); canvas.translate(keyDrawX, keyDrawY); params.mAnimAlpha = ALPHA_OPAQUE; params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE; if (!key.isSpacer()) { if (!key.isSpacer()) { onDrawKeyBackground(key, canvas, params); onDrawKeyBackground(key, canvas, params); } } Loading Loading @@ -860,15 +872,58 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } } private static class PreviewView extends RelativeLayout { KeyPreviewDrawParams mParams; Paint mGesturePaint; public PreviewView(Context context, KeyPreviewDrawParams params, Paint gesturePaint) { super(context); setWillNotDraw(false); mParams = params; mGesturePaint = gesturePaint; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(mParams.mCoordinates[0], mParams.mCoordinates[1]); PointerTracker.drawGestureTrailForAllPointerTrackers(canvas, mGesturePaint); } } private void addKeyPreview(TextView keyPreview) { private void addKeyPreview(TextView keyPreview) { if (mPreviewPlacer == null) { if (mPreviewPlacer == null) { mPreviewPlacer = new RelativeLayout(getContext()); createPreviewPlacer(); } mPreviewPlacer.addView( keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } private void createPreviewPlacer() { mPreviewPlacer = new PreviewView(getContext(), mKeyPreviewDrawParams, mGesturePaint); final ViewGroup windowContentView = final ViewGroup windowContentView = (ViewGroup)getRootView().findViewById(android.R.id.content); (ViewGroup)getRootView().findViewById(android.R.id.content); windowContentView.addView(mPreviewPlacer); windowContentView.addView(mPreviewPlacer); } } mPreviewPlacer.addView( keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); @Override public void showGestureTrail(PointerTracker tracker) { if (mPreviewPlacer == null) { createPreviewPlacer(); } final Rect r = tracker.getDrawingRect(); if (!r.isEmpty()) { // Invalidate the rectangular region encompassing the gesture. This is needed because // past points along the gesture will fade and gradually disappear. final KeyPreviewDrawParams params = mKeyPreviewDrawParams; mInvalidatedGesturesRect.set(r.left + params.mCoordinates[0] - GESTURE_DRAWING_WIDTH, r.top + params.mCoordinates[1] - GESTURE_DRAWING_WIDTH, r.right + params.mCoordinates[0] + GESTURE_DRAWING_WIDTH, r.bottom + params.mCoordinates[1] + GESTURE_DRAWING_WIDTH); mPreviewPlacer.invalidate(mInvalidatedGesturesRect); } else { mPreviewPlacer.invalidate(); } } } @SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16 @SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16 Loading java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +7 −5 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R; Loading Loading @@ -82,7 +83,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; private boolean mNeedsToDisplayLanguage; private boolean mNeedsToDisplayLanguage; private boolean mHasMultipleEnabledIMEsOrSubtypes; private boolean mHasMultipleEnabledIMEsOrSubtypes; private int mLanguageOnSpacebarAnimAlpha = ALPHA_OPAQUE; private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; private final float mSpacebarTextRatio; private final float mSpacebarTextRatio; private float mSpacebarTextSize; private float mSpacebarTextSize; private final int mSpacebarTextColor; private final int mSpacebarTextColor; Loading @@ -98,7 +99,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Stuff to draw altCodeWhileTyping keys. // Stuff to draw altCodeWhileTyping keys. private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; private int mAltCodeKeyWhileTypingAnimAlpha = ALPHA_OPAQUE; private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; // More keys keyboard // More keys keyboard private PopupWindow mMoreKeysWindow; private PopupWindow mMoreKeysWindow; Loading Loading @@ -361,7 +362,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mSpacebarTextShadowColor = a.getColor( mSpacebarTextShadowColor = a.getColor( R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); mLanguageOnSpacebarFinalAlpha = a.getInt( mLanguageOnSpacebarFinalAlpha = a.getInt( R.styleable.LatinKeyboardView_languageOnSpacebarFinalAlpha, ALPHA_OPAQUE); R.styleable.LatinKeyboardView_languageOnSpacebarFinalAlpha, Constants.Color.ALPHA_OPAQUE); final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId( final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId( R.styleable.LatinKeyboardView_languageOnSpacebarFadeoutAnimator, 0); R.styleable.LatinKeyboardView_languageOnSpacebarFadeoutAnimator, 0); final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId( final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId( Loading Loading @@ -468,7 +470,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE); mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE); mSpaceIcon = (mSpaceKey != null) mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon(keyboard.mIconsSet, ALPHA_OPAQUE) : null; ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; mSpacebarTextSize = keyHeight * mSpacebarTextRatio; mSpacebarTextSize = keyHeight * mSpacebarTextRatio; if (ProductionFlag.IS_EXPERIMENTAL) { if (ProductionFlag.IS_EXPERIMENTAL) { Loading Loading @@ -870,7 +872,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mNeedsToDisplayLanguage = false; mNeedsToDisplayLanguage = false; } else { } else { if (subtypeChanged && needsToDisplayLanguage) { if (subtypeChanged && needsToDisplayLanguage) { setLanguageOnSpacebarAnimAlpha(ALPHA_OPAQUE); setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); if (animator.isStarted()) { if (animator.isStarted()) { animator.cancel(); animator.cancel(); } } Loading java/src/com/android/inputmethod/keyboard/PointerTracker.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.inputmethod.keyboard; package com.android.inputmethod.keyboard; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.os.SystemClock; import android.os.SystemClock; import android.util.Log; import android.util.Log; import android.view.MotionEvent; import android.view.MotionEvent; Loading Loading @@ -76,6 +79,7 @@ public class PointerTracker { public TextView inflateKeyPreviewText(); public TextView inflateKeyPreviewText(); public void showKeyPreview(PointerTracker tracker); public void showKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); public void showGestureTrail(PointerTracker tracker); } } public interface TimerProxy { public interface TimerProxy { Loading Loading @@ -283,6 +287,15 @@ public class PointerTracker { sAggregratedPointers.reset(); sAggregratedPointers.reset(); } } // TODO: To handle multi-touch gestures we may want to move this method to // {@link PointerTrackerQueue}. public static void drawGestureTrailForAllPointerTrackers(Canvas canvas, Paint paint) { for (final PointerTracker tracker : sTrackers) { tracker.mGestureStroke.drawGestureTrail(canvas, paint, tracker.getLastX(), tracker.getLastY()); } } private PointerTracker(int id, KeyEventHandler handler) { private PointerTracker(int id, KeyEventHandler handler) { if (handler == null) if (handler == null) throw new NullPointerException(); throw new NullPointerException(); Loading Loading @@ -511,6 +524,9 @@ public class PointerTracker { public long getDownTime() { public long getDownTime() { return mDownTime; return mDownTime; } } public Rect getDrawingRect() { return mGestureStroke.getDrawingRect(); } private Key onDownKey(int x, int y, long eventTime) { private Key onDownKey(int x, int y, long eventTime) { mDownTime = eventTime; mDownTime = eventTime; Loading Loading @@ -696,6 +712,7 @@ public class PointerTracker { if (key != null && mInGesture) { if (key != null && mInGesture) { final InputPointers batchPoints = getIncrementalBatchPoints(); final InputPointers batchPoints = getIncrementalBatchPoints(); mDrawingProxy.showGestureTrail(this); if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) { if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) { updateBatchInput(batchPoints); updateBatchInput(batchPoints); } } Loading Loading @@ -868,6 +885,7 @@ public class PointerTracker { callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true); callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true); mCurrentKey = null; mCurrentKey = null; } } mDrawingProxy.showGestureTrail(this); return; return; } } // This event will be recognized as a regular code input. Clear unused batch points so they // This event will be recognized as a regular code input. Clear unused batch points so they Loading java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +38 −1 Original line number Original line Diff line number Diff line Loading @@ -14,8 +14,12 @@ package com.android.inputmethod.keyboard.internal; package com.android.inputmethod.keyboard.internal; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.FloatMath; import android.util.FloatMath; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.InputPointers; public class GestureStroke { public class GestureStroke { Loading @@ -35,6 +39,7 @@ public class GestureStroke { private int mMinGestureLength; private int mMinGestureLength; private int mMinGestureLengthWhileInGesture; private int mMinGestureLengthWhileInGesture; private int mMinGestureSampleLength; private int mMinGestureSampleLength; private final Rect mDrawingRect = new Rect(); // TODO: Move some of these to resource. // TODO: Move some of these to resource. private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f; private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f; Loading @@ -47,6 +52,10 @@ public class GestureStroke { private static final float DOUBLE_PI = (float)(2 * Math.PI); private static final float DOUBLE_PI = (float)(2 * Math.PI); // Fade based on number of gesture samples, see MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT private static final int DRAWING_GESTURE_FADE_START = 10; private static final int DRAWING_GESTURE_FADE_RATE = 6; public GestureStroke(int pointerId) { public GestureStroke(int pointerId) { mPointerId = pointerId; mPointerId = pointerId; reset(); reset(); Loading Loading @@ -77,6 +86,7 @@ public class GestureStroke { mLastIncrementalBatchSize = 0; mLastIncrementalBatchSize = 0; mLastPointTime = 0; mLastPointTime = 0; mInputPointers.reset(); mInputPointers.reset(); mDrawingRect.setEmpty(); } } private void updateLastPoint(final int x, final int y, final int time) { private void updateLastPoint(final int x, final int y, final int time) { Loading @@ -94,7 +104,6 @@ public class GestureStroke { } } return; return; } } final int[] xCoords = mInputPointers.getXCoordinates(); final int[] xCoords = mInputPointers.getXCoordinates(); final int[] yCoords = mInputPointers.getYCoordinates(); final int[] yCoords = mInputPointers.getYCoordinates(); final int lastX = xCoords[size - 1]; final int lastX = xCoords[size - 1]; Loading @@ -102,6 +111,11 @@ public class GestureStroke { final float dist = getDistance(lastX, lastY, x, y); final float dist = getDistance(lastX, lastY, x, y); if (dist > mMinGestureSampleLength) { if (dist > mMinGestureSampleLength) { mInputPointers.addPointer(x, y, mPointerId, time); mInputPointers.addPointer(x, y, mPointerId, time); if (mDrawingRect.isEmpty()) { mDrawingRect.set(x - 1, y - 1, x + 1, y + 1); } else { mDrawingRect.union(x, y); } mLength += dist; mLength += dist; final float angle = getAngle(lastX, lastY, x, y); final float angle = getAngle(lastX, lastY, x, y); if (size > 1) { if (size > 1) { Loading Loading @@ -161,4 +175,27 @@ public class GestureStroke { } } return diff; return diff; } } public void drawGestureTrail(Canvas canvas, Paint paint, int lastX, int lastY) { // 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 = mInputPointers.getPointerSize(); int[] xCoords = mInputPointers.getXCoordinates(); int[] yCoords = mInputPointers.getYCoordinates(); 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); if (i == size - 1) { canvas.drawLine(lastX, lastY, xCoords[i], yCoords[i], paint); } } } public Rect getDrawingRect() { return mDrawingRect; } } } java/src/com/android/inputmethod/latin/Constants.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,13 @@ package com.android.inputmethod.latin; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo; public final class Constants { public final class Constants { public static final class Color { /** * The alpha value for fully opaque. */ public final static int ALPHA_OPAQUE = 255; } public static final class ImeOption { public static final class ImeOption { /** /** * The private IME option used to indicate that no microphone should be shown for a given * The private IME option used to indicate that no microphone should be shown for a given Loading Loading
java/src/com/android/inputmethod/keyboard/KeyboardView.java +62 −7 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.view.ViewGroup; import android.widget.RelativeLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.TextView; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; Loading Loading @@ -94,7 +95,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // The maximum key label width in the proportion to the key width. // The maximum key label width in the proportion to the key width. private static final float MAX_LABEL_RATIO = 0.90f; private static final float MAX_LABEL_RATIO = 0.90f; public final static int ALPHA_OPAQUE = 255; private final static int GESTURE_DRAWING_WIDTH = 5; private final static int GESTURE_DRAWING_COLOR = 0xff33b5e5; // Main keyboard // Main keyboard private Keyboard mKeyboard; private Keyboard mKeyboard; Loading @@ -118,11 +120,14 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final HashSet<Key> mInvalidatedKeys = new HashSet<Key>(); private final HashSet<Key> mInvalidatedKeys = new HashSet<Key>(); /** The region of invalidated keys */ /** The region of invalidated keys */ private final Rect mInvalidatedKeysRect = new Rect(); private final Rect mInvalidatedKeysRect = new Rect(); /** The region of invalidated gestures */ private final Rect mInvalidatedGesturesRect = new Rect(); /** The keyboard bitmap buffer for faster updates */ /** The keyboard bitmap buffer for faster updates */ private Bitmap mBuffer; private Bitmap mBuffer; /** The canvas for the above mutable keyboard bitmap */ /** The canvas for the above mutable keyboard bitmap */ private Canvas mCanvas; private Canvas mCanvas; private final Paint mPaint = new Paint(); private final Paint mPaint = new Paint(); private final Paint mGesturePaint = new Paint(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); // This sparse array caches key label text height in pixel indexed by key label text size. // This sparse array caches key label text height in pixel indexed by key label text size. private static final SparseArray<Float> sTextHeightCache = new SparseArray<Float>(); private static final SparseArray<Float> sTextHeightCache = new SparseArray<Float>(); Loading Loading @@ -264,7 +269,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public void blendAlpha(Paint paint) { public void blendAlpha(Paint paint) { final int color = paint.getColor(); final int color = paint.getColor(); paint.setARGB((paint.getAlpha() * mAnimAlpha) / ALPHA_OPAQUE, paint.setARGB((paint.getAlpha() * mAnimAlpha) / Constants.Color.ALPHA_OPAQUE, Color.red(color), Color.green(color), Color.blue(color)); Color.red(color), Color.green(color), Color.blue(color)); } } } } Loading Loading @@ -372,6 +377,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mPaint.setAntiAlias(true); mPaint.setAntiAlias(true); // TODO: These paint parameters should be specified via attribute of the view and styleable. mGesturePaint.setAntiAlias(true); mGesturePaint.setStyle(Paint.Style.STROKE); mGesturePaint.setStrokeJoin(Paint.Join.ROUND); mGesturePaint.setColor(GESTURE_DRAWING_COLOR); mGesturePaint.setStrokeWidth(GESTURE_DRAWING_WIDTH); } } // Read fraction value in TypedArray as float. // Read fraction value in TypedArray as float. Loading Loading @@ -517,7 +529,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final int keyDrawY = key.mY + getPaddingTop(); final int keyDrawY = key.mY + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); canvas.translate(keyDrawX, keyDrawY); params.mAnimAlpha = ALPHA_OPAQUE; params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE; if (!key.isSpacer()) { if (!key.isSpacer()) { onDrawKeyBackground(key, canvas, params); onDrawKeyBackground(key, canvas, params); } } Loading Loading @@ -860,15 +872,58 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } } private static class PreviewView extends RelativeLayout { KeyPreviewDrawParams mParams; Paint mGesturePaint; public PreviewView(Context context, KeyPreviewDrawParams params, Paint gesturePaint) { super(context); setWillNotDraw(false); mParams = params; mGesturePaint = gesturePaint; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(mParams.mCoordinates[0], mParams.mCoordinates[1]); PointerTracker.drawGestureTrailForAllPointerTrackers(canvas, mGesturePaint); } } private void addKeyPreview(TextView keyPreview) { private void addKeyPreview(TextView keyPreview) { if (mPreviewPlacer == null) { if (mPreviewPlacer == null) { mPreviewPlacer = new RelativeLayout(getContext()); createPreviewPlacer(); } mPreviewPlacer.addView( keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } private void createPreviewPlacer() { mPreviewPlacer = new PreviewView(getContext(), mKeyPreviewDrawParams, mGesturePaint); final ViewGroup windowContentView = final ViewGroup windowContentView = (ViewGroup)getRootView().findViewById(android.R.id.content); (ViewGroup)getRootView().findViewById(android.R.id.content); windowContentView.addView(mPreviewPlacer); windowContentView.addView(mPreviewPlacer); } } mPreviewPlacer.addView( keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); @Override public void showGestureTrail(PointerTracker tracker) { if (mPreviewPlacer == null) { createPreviewPlacer(); } final Rect r = tracker.getDrawingRect(); if (!r.isEmpty()) { // Invalidate the rectangular region encompassing the gesture. This is needed because // past points along the gesture will fade and gradually disappear. final KeyPreviewDrawParams params = mKeyPreviewDrawParams; mInvalidatedGesturesRect.set(r.left + params.mCoordinates[0] - GESTURE_DRAWING_WIDTH, r.top + params.mCoordinates[1] - GESTURE_DRAWING_WIDTH, r.right + params.mCoordinates[0] + GESTURE_DRAWING_WIDTH, r.bottom + params.mCoordinates[1] + GESTURE_DRAWING_WIDTH); mPreviewPlacer.invalidate(mInvalidatedGesturesRect); } else { mPreviewPlacer.invalidate(); } } } @SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16 @SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16 Loading
java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +7 −5 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R; Loading Loading @@ -82,7 +83,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; private boolean mNeedsToDisplayLanguage; private boolean mNeedsToDisplayLanguage; private boolean mHasMultipleEnabledIMEsOrSubtypes; private boolean mHasMultipleEnabledIMEsOrSubtypes; private int mLanguageOnSpacebarAnimAlpha = ALPHA_OPAQUE; private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; private final float mSpacebarTextRatio; private final float mSpacebarTextRatio; private float mSpacebarTextSize; private float mSpacebarTextSize; private final int mSpacebarTextColor; private final int mSpacebarTextColor; Loading @@ -98,7 +99,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Stuff to draw altCodeWhileTyping keys. // Stuff to draw altCodeWhileTyping keys. private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; private int mAltCodeKeyWhileTypingAnimAlpha = ALPHA_OPAQUE; private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; // More keys keyboard // More keys keyboard private PopupWindow mMoreKeysWindow; private PopupWindow mMoreKeysWindow; Loading Loading @@ -361,7 +362,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mSpacebarTextShadowColor = a.getColor( mSpacebarTextShadowColor = a.getColor( R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); mLanguageOnSpacebarFinalAlpha = a.getInt( mLanguageOnSpacebarFinalAlpha = a.getInt( R.styleable.LatinKeyboardView_languageOnSpacebarFinalAlpha, ALPHA_OPAQUE); R.styleable.LatinKeyboardView_languageOnSpacebarFinalAlpha, Constants.Color.ALPHA_OPAQUE); final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId( final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId( R.styleable.LatinKeyboardView_languageOnSpacebarFadeoutAnimator, 0); R.styleable.LatinKeyboardView_languageOnSpacebarFadeoutAnimator, 0); final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId( final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId( Loading Loading @@ -468,7 +470,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE); mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE); mSpaceIcon = (mSpaceKey != null) mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon(keyboard.mIconsSet, ALPHA_OPAQUE) : null; ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; mSpacebarTextSize = keyHeight * mSpacebarTextRatio; mSpacebarTextSize = keyHeight * mSpacebarTextRatio; if (ProductionFlag.IS_EXPERIMENTAL) { if (ProductionFlag.IS_EXPERIMENTAL) { Loading Loading @@ -870,7 +872,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mNeedsToDisplayLanguage = false; mNeedsToDisplayLanguage = false; } else { } else { if (subtypeChanged && needsToDisplayLanguage) { if (subtypeChanged && needsToDisplayLanguage) { setLanguageOnSpacebarAnimAlpha(ALPHA_OPAQUE); setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); if (animator.isStarted()) { if (animator.isStarted()) { animator.cancel(); animator.cancel(); } } Loading
java/src/com/android/inputmethod/keyboard/PointerTracker.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.inputmethod.keyboard; package com.android.inputmethod.keyboard; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.os.SystemClock; import android.os.SystemClock; import android.util.Log; import android.util.Log; import android.view.MotionEvent; import android.view.MotionEvent; Loading Loading @@ -76,6 +79,7 @@ public class PointerTracker { public TextView inflateKeyPreviewText(); public TextView inflateKeyPreviewText(); public void showKeyPreview(PointerTracker tracker); public void showKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); public void showGestureTrail(PointerTracker tracker); } } public interface TimerProxy { public interface TimerProxy { Loading Loading @@ -283,6 +287,15 @@ public class PointerTracker { sAggregratedPointers.reset(); sAggregratedPointers.reset(); } } // TODO: To handle multi-touch gestures we may want to move this method to // {@link PointerTrackerQueue}. public static void drawGestureTrailForAllPointerTrackers(Canvas canvas, Paint paint) { for (final PointerTracker tracker : sTrackers) { tracker.mGestureStroke.drawGestureTrail(canvas, paint, tracker.getLastX(), tracker.getLastY()); } } private PointerTracker(int id, KeyEventHandler handler) { private PointerTracker(int id, KeyEventHandler handler) { if (handler == null) if (handler == null) throw new NullPointerException(); throw new NullPointerException(); Loading Loading @@ -511,6 +524,9 @@ public class PointerTracker { public long getDownTime() { public long getDownTime() { return mDownTime; return mDownTime; } } public Rect getDrawingRect() { return mGestureStroke.getDrawingRect(); } private Key onDownKey(int x, int y, long eventTime) { private Key onDownKey(int x, int y, long eventTime) { mDownTime = eventTime; mDownTime = eventTime; Loading Loading @@ -696,6 +712,7 @@ public class PointerTracker { if (key != null && mInGesture) { if (key != null && mInGesture) { final InputPointers batchPoints = getIncrementalBatchPoints(); final InputPointers batchPoints = getIncrementalBatchPoints(); mDrawingProxy.showGestureTrail(this); if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) { if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) { updateBatchInput(batchPoints); updateBatchInput(batchPoints); } } Loading Loading @@ -868,6 +885,7 @@ public class PointerTracker { callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true); callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true); mCurrentKey = null; mCurrentKey = null; } } mDrawingProxy.showGestureTrail(this); return; return; } } // This event will be recognized as a regular code input. Clear unused batch points so they // This event will be recognized as a regular code input. Clear unused batch points so they Loading
java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +38 −1 Original line number Original line Diff line number Diff line Loading @@ -14,8 +14,12 @@ package com.android.inputmethod.keyboard.internal; package com.android.inputmethod.keyboard.internal; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.FloatMath; import android.util.FloatMath; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.InputPointers; public class GestureStroke { public class GestureStroke { Loading @@ -35,6 +39,7 @@ public class GestureStroke { private int mMinGestureLength; private int mMinGestureLength; private int mMinGestureLengthWhileInGesture; private int mMinGestureLengthWhileInGesture; private int mMinGestureSampleLength; private int mMinGestureSampleLength; private final Rect mDrawingRect = new Rect(); // TODO: Move some of these to resource. // TODO: Move some of these to resource. private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f; private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f; Loading @@ -47,6 +52,10 @@ public class GestureStroke { private static final float DOUBLE_PI = (float)(2 * Math.PI); private static final float DOUBLE_PI = (float)(2 * Math.PI); // Fade based on number of gesture samples, see MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT private static final int DRAWING_GESTURE_FADE_START = 10; private static final int DRAWING_GESTURE_FADE_RATE = 6; public GestureStroke(int pointerId) { public GestureStroke(int pointerId) { mPointerId = pointerId; mPointerId = pointerId; reset(); reset(); Loading Loading @@ -77,6 +86,7 @@ public class GestureStroke { mLastIncrementalBatchSize = 0; mLastIncrementalBatchSize = 0; mLastPointTime = 0; mLastPointTime = 0; mInputPointers.reset(); mInputPointers.reset(); mDrawingRect.setEmpty(); } } private void updateLastPoint(final int x, final int y, final int time) { private void updateLastPoint(final int x, final int y, final int time) { Loading @@ -94,7 +104,6 @@ public class GestureStroke { } } return; return; } } final int[] xCoords = mInputPointers.getXCoordinates(); final int[] xCoords = mInputPointers.getXCoordinates(); final int[] yCoords = mInputPointers.getYCoordinates(); final int[] yCoords = mInputPointers.getYCoordinates(); final int lastX = xCoords[size - 1]; final int lastX = xCoords[size - 1]; Loading @@ -102,6 +111,11 @@ public class GestureStroke { final float dist = getDistance(lastX, lastY, x, y); final float dist = getDistance(lastX, lastY, x, y); if (dist > mMinGestureSampleLength) { if (dist > mMinGestureSampleLength) { mInputPointers.addPointer(x, y, mPointerId, time); mInputPointers.addPointer(x, y, mPointerId, time); if (mDrawingRect.isEmpty()) { mDrawingRect.set(x - 1, y - 1, x + 1, y + 1); } else { mDrawingRect.union(x, y); } mLength += dist; mLength += dist; final float angle = getAngle(lastX, lastY, x, y); final float angle = getAngle(lastX, lastY, x, y); if (size > 1) { if (size > 1) { Loading Loading @@ -161,4 +175,27 @@ public class GestureStroke { } } return diff; return diff; } } public void drawGestureTrail(Canvas canvas, Paint paint, int lastX, int lastY) { // 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 = mInputPointers.getPointerSize(); int[] xCoords = mInputPointers.getXCoordinates(); int[] yCoords = mInputPointers.getYCoordinates(); 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); if (i == size - 1) { canvas.drawLine(lastX, lastY, xCoords[i], yCoords[i], paint); } } } public Rect getDrawingRect() { return mDrawingRect; } } }
java/src/com/android/inputmethod/latin/Constants.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,13 @@ package com.android.inputmethod.latin; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo; public final class Constants { public final class Constants { public static final class Color { /** * The alpha value for fully opaque. */ public final static int ALPHA_OPAQUE = 255; } public static final class ImeOption { public static final class ImeOption { /** /** * The private IME option used to indicate that no microphone should be shown for a given * The private IME option used to indicate that no microphone should be shown for a given Loading