Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 157fe98f authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Draw gesture trail that is above the keyboard

Bug: 7233992
Change-Id: Ia848543a9d008c68d6ecbc7f715aa6ccdba9d1c6
parent 002a502c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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");
+15 −13
Original line number Diff line number Diff line
@@ -576,7 +576,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
        mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
    }

    private void updateBatchInput(final long eventTime) {
    private void mayUpdateBatchInput(final long eventTime, final Key key) {
        if (key != null) {
            synchronized (sAggregratedPointers) {
                mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers);
                final int size = sAggregratedPointers.getPointerSize();
@@ -590,6 +591,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
                    mListener.onUpdateBatchInput(sAggregratedPointers);
                }
            }
        }
        final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
        mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
    }
@@ -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);
            }
        }
    }
+79 −32
Original line number Diff line number Diff line
@@ -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,29 +214,68 @@ 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);
            }
            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.
            }
            if (needsUpdatingGesturePreviewTrail) {
                mDrawingHandler.postUpdateGestureTrailPreview();
            }
        }
        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.
                mGesturePaint.setColor(Color.TRANSPARENT);
                mGesturePaint.setStyle(Paint.Style.FILL);
                mOffscreenCanvas.drawRect(mOffscreenDirtyRect, mGesturePaint);
                mOffscreenDirtyRect.setEmpty();
        if (!dirtyRect.isEmpty()) {
            paint.setColor(Color.TRANSPARENT);
            paint.setStyle(Paint.Style.FILL);
            offscreenCanvas.drawRect(dirtyRect, paint);
        }
        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.
@@ -234,26 +283,24 @@ public class PreviewPlacerView extends RelativeLayout {
            for (int index = 0; index < trailsCount; index++) {
                final GesturePreviewTrail trail = mGesturePreviewTrails.valueAt(index);
                needsUpdatingGesturePreviewTrail |=
                            trail.drawGestureTrail(mOffscreenCanvas, mGesturePaint,
                        trail.drawGestureTrail(offscreenCanvas, paint,
                                mGesturePreviewTrailBoundsRect, mGesturePreviewTrailParams);
                // {@link #mGesturePreviewTrailBoundsRect} has bounding box of the trail.
                    mOffscreenDirtyRect.union(mGesturePreviewTrailBoundsRect);
                }
            }
            if (!mOffscreenDirtyRect.isEmpty()) {
                canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect,
                        mGesturePaint);
                // Note: Defer clearing the dirty rectangle here because we will get cleared
                // rectangle on the canvas.
            }
            if (needsUpdatingGesturePreviewTrail) {
                mDrawingHandler.postUpdateGestureTrailPreview();
                dirtyRect.union(mGesturePreviewTrailBoundsRect);
            }
        }
        if (mDrawsGestureFloatingPreviewText) {
            drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
        offscreenCanvas.translate(0, -mOffscreenOffsetY);

        // Clip dirty rectangle with offscreen buffer width/height.
        dirtyRect.offset(0, mOffscreenOffsetY);
        clipRect(dirtyRect, 0, 0, mOffscreenWidth, mOffscreenHeight);
        return needsUpdatingGesturePreviewTrail;
    }
        canvas.translate(-mXOrigin, -mYOrigin);

    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) {