From 157fe98fd439a7d9cc063a7f5573f688e33c2f29 Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Wed, 26 Sep 2012 15:49:23 +0900
Subject: [PATCH] Draw gesture trail that is above the keyboard

Bug: 7233992
Change-Id: Ia848543a9d008c68d6ecbc7f715aa6ccdba9d1c6
---
 .../inputmethod/keyboard/KeyboardView.java    |   3 +-
 .../inputmethod/keyboard/PointerTracker.java  |  28 +++--
 .../keyboard/internal/PreviewPlacerView.java  | 111 +++++++++++++-----
 3 files changed, 96 insertions(+), 46 deletions(-)

diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d51e036b1a..a9856e1218 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -826,7 +826,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
         }
         final int[] viewOrigin = new int[2];
         getLocationInWindow(viewOrigin);
-        mPreviewPlacerView.setOrigin(viewOrigin[0], viewOrigin[1]);
+        mPreviewPlacerView.setKeyboardViewGeometry(
+                viewOrigin[0], viewOrigin[1], getWidth(), getHeight());
         final View rootView = getRootView();
         if (rootView == null) {
             Log.w(TAG, "Cannot find root view");
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index cfd1e09f90..ec8f659946 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -576,18 +576,20 @@ public class PointerTracker implements PointerTrackerQueue.Element {
         mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
     }
 
-    private void updateBatchInput(final long eventTime) {
-        synchronized (sAggregratedPointers) {
-            mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers);
-            final int size = sAggregratedPointers.getPointerSize();
-            if (size > sLastRecognitionPointSize
-                    && GestureStroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
-                sLastRecognitionPointSize = size;
-                sLastRecognitionTime = eventTime;
-                if (DEBUG_LISTENER) {
-                    Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size);
+    private void mayUpdateBatchInput(final long eventTime, final Key key) {
+        if (key != null) {
+            synchronized (sAggregratedPointers) {
+                mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers);
+                final int size = sAggregratedPointers.getPointerSize();
+                if (size > sLastRecognitionPointSize
+                        && GestureStroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
+                    sLastRecognitionPointSize = size;
+                    sLastRecognitionTime = eventTime;
+                    if (DEBUG_LISTENER) {
+                        Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size);
+                    }
+                    mListener.onUpdateBatchInput(sAggregratedPointers);
                 }
-                mListener.onUpdateBatchInput(sAggregratedPointers);
             }
         }
         final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
@@ -746,8 +748,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
         if (mIsDetectingGesture) {
             mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent);
             mayStartBatchInput(key);
-            if (sInGesture && key != null) {
-                updateBatchInput(eventTime);
+            if (sInGesture) {
+                mayUpdateBatchInput(eventTime, key);
             }
         }
     }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index b3fd284b18..72be7fc590 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -40,6 +40,10 @@ import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
 
 public class PreviewPlacerView extends RelativeLayout {
+    // The height of extra area above the keyboard to draw gesture trails.
+    // Proportional to the keyboard height.
+    private static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f;
+
     private final int mGestureFloatingPreviewTextColor;
     private final int mGestureFloatingPreviewTextOffset;
     private final int mGestureFloatingPreviewColor;
@@ -47,14 +51,17 @@ public class PreviewPlacerView extends RelativeLayout {
     private final float mGestureFloatingPreviewVerticalPadding;
     private final float mGestureFloatingPreviewRoundRadius;
 
-    private int mXOrigin;
-    private int mYOrigin;
+    private int mKeyboardViewOriginX;
+    private int mKeyboardViewOriginY;
 
     private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails =
             CollectionUtils.newSparseArray();
     private final Params mGesturePreviewTrailParams;
     private final Paint mGesturePaint;
     private boolean mDrawsGesturePreviewTrail;
+    private int mOffscreenWidth;
+    private int mOffscreenHeight;
+    private int mOffscreenOffsetY;
     private Bitmap mOffscreenBuffer;
     private final Canvas mOffscreenCanvas = new Canvas();
     private final Rect mOffscreenDirtyRect = new Rect();
@@ -165,9 +172,12 @@ public class PreviewPlacerView extends RelativeLayout {
         setLayerType(LAYER_TYPE_HARDWARE, layerPaint);
     }
 
-    public void setOrigin(final int x, final int y) {
-        mXOrigin = x;
-        mYOrigin = y;
+    public void setKeyboardViewGeometry(final int x, final int y, final int w, final int h) {
+        mKeyboardViewOriginX = x;
+        mKeyboardViewOriginY = y;
+        mOffscreenOffsetY = (int)(h * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
+        mOffscreenWidth = w;
+        mOffscreenHeight = mOffscreenOffsetY + h;
     }
 
     public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail,
@@ -204,45 +214,42 @@ public class PreviewPlacerView extends RelativeLayout {
 
     @Override
     protected void onDetachedFromWindow() {
+        freeOffscreenBuffer();
+    }
+
+    private void freeOffscreenBuffer() {
         if (mOffscreenBuffer != null) {
             mOffscreenBuffer.recycle();
             mOffscreenBuffer = null;
         }
     }
 
+    private void mayAllocateOffscreenBuffer() {
+        if (mOffscreenBuffer != null && mOffscreenBuffer.getWidth() == mOffscreenWidth
+                && mOffscreenBuffer.getHeight() == mOffscreenHeight) {
+            return;
+        }
+        freeOffscreenBuffer();
+        mOffscreenBuffer = Bitmap.createBitmap(
+                mOffscreenWidth, mOffscreenHeight, Bitmap.Config.ARGB_8888);
+        mOffscreenCanvas.setBitmap(mOffscreenBuffer);
+    }
+
     @Override
     public void onDraw(final Canvas canvas) {
         super.onDraw(canvas);
-        canvas.translate(mXOrigin, mYOrigin);
         if (mDrawsGesturePreviewTrail) {
-            if (mOffscreenBuffer == null) {
-                mOffscreenBuffer = Bitmap.createBitmap(
-                        getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
-                mOffscreenCanvas.setBitmap(mOffscreenBuffer);
-            }
-            if (!mOffscreenDirtyRect.isEmpty()) {
-                // Clear previous dirty rectangle.
-                mGesturePaint.setColor(Color.TRANSPARENT);
-                mGesturePaint.setStyle(Paint.Style.FILL);
-                mOffscreenCanvas.drawRect(mOffscreenDirtyRect, mGesturePaint);
-                mOffscreenDirtyRect.setEmpty();
-            }
-            boolean needsUpdatingGesturePreviewTrail = false;
-            synchronized (mGesturePreviewTrails) {
-                // Trails count == fingers count that have ever been active.
-                final int trailsCount = mGesturePreviewTrails.size();
-                for (int index = 0; index < trailsCount; index++) {
-                    final GesturePreviewTrail trail = mGesturePreviewTrails.valueAt(index);
-                    needsUpdatingGesturePreviewTrail |=
-                            trail.drawGestureTrail(mOffscreenCanvas, mGesturePaint,
-                                    mGesturePreviewTrailBoundsRect, mGesturePreviewTrailParams);
-                    // {@link #mGesturePreviewTrailBoundsRect} has bounding box of the trail.
-                    mOffscreenDirtyRect.union(mGesturePreviewTrailBoundsRect);
-                }
-            }
+            mayAllocateOffscreenBuffer();
+            // Draw gesture trails to offscreen buffer.
+            final boolean needsUpdatingGesturePreviewTrail = drawGestureTrails(
+                    mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect);
+            // Transfer offscreen buffer to screen.
             if (!mOffscreenDirtyRect.isEmpty()) {
+                final int offsetY = mKeyboardViewOriginY - mOffscreenOffsetY;
+                canvas.translate(mKeyboardViewOriginX, offsetY);
                 canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect,
                         mGesturePaint);
+                canvas.translate(-mKeyboardViewOriginX, -offsetY);
                 // Note: Defer clearing the dirty rectangle here because we will get cleared
                 // rectangle on the canvas.
             }
@@ -251,9 +258,49 @@ public class PreviewPlacerView extends RelativeLayout {
             }
         }
         if (mDrawsGestureFloatingPreviewText) {
+            canvas.translate(mKeyboardViewOriginX, mKeyboardViewOriginY);
             drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
+            canvas.translate(-mKeyboardViewOriginX, -mKeyboardViewOriginY);
+        }
+    }
+
+    private boolean drawGestureTrails(final Canvas offscreenCanvas, final Paint paint,
+            final Rect dirtyRect) {
+        // Clear previous dirty rectangle.
+        if (!dirtyRect.isEmpty()) {
+            paint.setColor(Color.TRANSPARENT);
+            paint.setStyle(Paint.Style.FILL);
+            offscreenCanvas.drawRect(dirtyRect, paint);
         }
-        canvas.translate(-mXOrigin, -mYOrigin);
+        dirtyRect.setEmpty();
+
+        // Draw gesture trails to offscreen buffer.
+        offscreenCanvas.translate(0, mOffscreenOffsetY);
+        boolean needsUpdatingGesturePreviewTrail = false;
+        synchronized (mGesturePreviewTrails) {
+            // Trails count == fingers count that have ever been active.
+            final int trailsCount = mGesturePreviewTrails.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);
+            }
+        }
+        offscreenCanvas.translate(0, -mOffscreenOffsetY);
+
+        // Clip dirty rectangle with offscreen buffer width/height.
+        dirtyRect.offset(0, mOffscreenOffsetY);
+        clipRect(dirtyRect, 0, 0, mOffscreenWidth, mOffscreenHeight);
+        return needsUpdatingGesturePreviewTrail;
+    }
+
+    private static void clipRect(final Rect out, final int left, final int top, final int right,
+            final int bottom) {
+        out.set(Math.max(out.left, left), Math.max(out.top, top), Math.min(out.right, right),
+                Math.min(out.bottom, bottom));
     }
 
     public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
-- 
GitLab