summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Haoyu Zhang <haoyuchang@google.com> 2023-01-24 15:37:25 -0800
committer Haoyu Zhang <haoyuchang@google.com> 2023-01-24 15:39:02 -0800
commit6709bf62a3b89738b3545635ae8067bee5437eed (patch)
treef030715e8e000017dda28d82a13854a8d65e93f8
parenta428d82f2f92e6c8a2984ed7b4ecc45539528cd1 (diff)
Update HandwritingIme to show bounds information
Bug: N/A Test: manually tested Change-Id: Id0ae8a133901b26c1a04143d061a460e76c7bc4b
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java116
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java99
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java16
3 files changed, 220 insertions, 11 deletions
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java
new file mode 100644
index 000000000000..6b924f335ef7
--- /dev/null
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 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.google.android.test.handwritingime;
+
+import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_EDITOR_BOUNDS;
+import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_NONE;
+import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_VISIBLE_LINE_BOUNDS;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.view.View;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.EditorBoundsInfo;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.graphics.ColorUtils;
+
+import java.util.List;
+
+public class BoundsInfoDrawHelper {
+ private static final Paint sPaint = new Paint();
+ private static final int EDITOR_BOUNDS_COLOR =
+ ColorUtils.setAlphaComponent(Color.DKGRAY, 128);
+ private static final int HANDWRITING_BOUNDS_COLOR =
+ ColorUtils.setAlphaComponent(Color.BLUE, 128);
+ private static final int VISIBLE_LINE_BOUNDS_COLOR =
+ ColorUtils.setAlphaComponent(Color.MAGENTA, 128);
+
+ public static void draw(Canvas canvas, View inkView, int boundsInfoMode,
+ CursorAnchorInfo cursorAnchorInfo) {
+ if (boundsInfoMode == BOUNDS_INFO_NONE || cursorAnchorInfo == null) {
+ return;
+ }
+
+ // The matrix in CursorAnchorInfo transforms the editor coordinates to on-screen
+ // coordinates. We then transform the matrix from the on-screen coordinates to the
+ // inkView's coordinates. So the result matrix transforms the editor coordinates
+ // to the inkView coordinates.
+ final Matrix matrix = cursorAnchorInfo.getMatrix();
+ inkView.transformMatrixToLocal(matrix);
+
+ if ((boundsInfoMode & BOUNDS_INFO_EDITOR_BOUNDS) != 0) {
+ drawEditorBoundsInfo(canvas, matrix, cursorAnchorInfo.getEditorBoundsInfo());
+ }
+
+ if ((boundsInfoMode & BOUNDS_INFO_VISIBLE_LINE_BOUNDS) != 0) {
+ drawVisibleLineBounds(canvas, matrix, cursorAnchorInfo.getVisibleLineBounds());
+ }
+ }
+
+ private static void setPaintForEditorBoundsInfo() {
+ sPaint.reset();
+ sPaint.setStyle(Paint.Style.STROKE);
+ sPaint.setStrokeWidth(5f);
+ }
+
+ private static void drawEditorBoundsInfo(Canvas canvas, Matrix matrix,
+ @Nullable EditorBoundsInfo editorBoundsInfo) {
+ if (editorBoundsInfo == null) {
+ return;
+ }
+ final RectF editorBounds = editorBoundsInfo.getEditorBounds();
+ setPaintForEditorBoundsInfo();
+ if (editorBounds != null) {
+ final RectF localEditorBounds = new RectF(editorBounds);
+ matrix.mapRect(localEditorBounds);
+ sPaint.setColor(EDITOR_BOUNDS_COLOR);
+ canvas.drawRect(localEditorBounds, sPaint);
+ }
+
+ final RectF handwritingBounds = editorBoundsInfo.getHandwritingBounds();
+ if (handwritingBounds != null) {
+ final RectF localHandwritingBounds = new RectF(handwritingBounds);
+ matrix.mapRect(localHandwritingBounds);
+ sPaint.setColor(HANDWRITING_BOUNDS_COLOR);
+ canvas.drawRect(localHandwritingBounds, sPaint);
+ }
+ }
+
+ private static void setPaintForVisibleLineBounds() {
+ sPaint.reset();
+ sPaint.setStyle(Paint.Style.STROKE);
+ sPaint.setStrokeWidth(2f);
+ sPaint.setColor(VISIBLE_LINE_BOUNDS_COLOR);
+ }
+
+ private static void drawVisibleLineBounds(Canvas canvas, Matrix matrix,
+ List<RectF> visibleLineBounds) {
+ if (visibleLineBounds.isEmpty()) {
+ return;
+ }
+ setPaintForVisibleLineBounds();
+ for (RectF lineBound : visibleLineBounds) {
+ matrix.mapRect(lineBound);
+ canvas.drawRect(lineBound, sPaint);
+ }
+ }
+}
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
index 2fd236895467..8380dcf4b4a4 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
@@ -25,7 +25,9 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.DeleteGesture;
+import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.HandwritingGesture;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InsertGesture;
@@ -34,6 +36,7 @@ import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Spinner;
@@ -43,9 +46,6 @@ import java.util.Random;
import java.util.function.IntConsumer;
public class HandwritingIme extends InputMethodService {
-
- public static final int HEIGHT_DP = 100;
-
private static final int OP_NONE = 0;
private static final int OP_SELECT = 1;
private static final int OP_DELETE = 2;
@@ -62,6 +62,12 @@ public class HandwritingIme extends InputMethodService {
private Spinner mRichGestureGranularitySpinner;
private PointF mRichGestureStartPoint;
+ static final int BOUNDS_INFO_NONE = 0;
+ static final int BOUNDS_INFO_VISIBLE_LINE_BOUNDS = 1;
+ static final int BOUNDS_INFO_EDITOR_BOUNDS = 2;
+ private int mBoundsInfoMode = BOUNDS_INFO_NONE;
+ private LinearLayout mBoundsInfoCheckBoxes;
+
private final IntConsumer mResultConsumer = value -> Log.d(TAG, "Gesture result: " + value);
interface HandwritingFinisher {
@@ -201,12 +207,7 @@ public class HandwritingIme extends InputMethodService {
public View onCreateInputView() {
Log.d(TAG, "onCreateInputView");
final ViewGroup view = new FrameLayout(this);
- final View inner = new View(this);
- final float density = getResources().getDisplayMetrics().density;
- final int height = (int) (HEIGHT_DP * density);
view.setPadding(0, 0, 0, 0);
- view.addView(inner, new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT, height));
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(new LinearLayout.LayoutParams(
@@ -214,9 +215,9 @@ public class HandwritingIme extends InputMethodService {
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(getRichGestureActionsSpinner());
layout.addView(getRichGestureGranularitySpinner());
-
+ layout.addView(getBoundsInfoCheckBoxes());
+ layout.setBackgroundColor(getColor(R.color.holo_green_light));
view.addView(layout);
- inner.setBackgroundColor(getColor(R.color.holo_green_light));
return view;
}
@@ -228,7 +229,7 @@ public class HandwritingIme extends InputMethodService {
mRichGestureModeSpinner = new Spinner(this);
mRichGestureModeSpinner.setPadding(100, 0, 100, 0);
mRichGestureModeSpinner.setTooltipText("Handwriting IME mode");
- String[] items = new String[] {
+ String[] items = new String[]{
"Handwriting IME - Rich gesture disabled",
"Rich gesture SELECT",
"Rich gesture DELETE",
@@ -259,6 +260,69 @@ public class HandwritingIme extends InputMethodService {
return mRichGestureModeSpinner;
}
+ private void updateCursorAnchorInfo(int boundsInfoMode) {
+ final InputConnection ic = getCurrentInputConnection();
+ if (ic == null) return;
+
+ if (boundsInfoMode == BOUNDS_INFO_NONE) {
+ ic.requestCursorUpdates(0);
+ return;
+ }
+
+ final int cursorUpdateMode = InputConnection.CURSOR_UPDATE_MONITOR;
+ int cursorUpdateFilter = 0;
+ if ((boundsInfoMode & BOUNDS_INFO_EDITOR_BOUNDS) != 0) {
+ cursorUpdateFilter |= InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS;
+ }
+
+ if ((boundsInfoMode & BOUNDS_INFO_VISIBLE_LINE_BOUNDS) != 0) {
+ cursorUpdateFilter |= InputConnection.CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS;
+ }
+ ic.requestCursorUpdates(cursorUpdateMode | cursorUpdateFilter);
+ }
+
+ private void updateBoundsInfoMode() {
+ if (mInk != null) {
+ mInk.setBoundsInfoMode(mBoundsInfoMode);
+ }
+ updateCursorAnchorInfo(mBoundsInfoMode);
+ }
+
+ private View getBoundsInfoCheckBoxes() {
+ if (mBoundsInfoCheckBoxes != null) {
+ return mBoundsInfoCheckBoxes;
+ }
+ mBoundsInfoCheckBoxes = new LinearLayout(this);
+ mBoundsInfoCheckBoxes.setPadding(100, 0, 100, 0);
+ mBoundsInfoCheckBoxes.setOrientation(LinearLayout.HORIZONTAL);
+
+ final CheckBox editorBoundsInfoCheckBox = new CheckBox(this);
+ editorBoundsInfoCheckBox.setText("EditorBoundsInfo");
+ editorBoundsInfoCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ if (isChecked) {
+ mBoundsInfoMode |= BOUNDS_INFO_EDITOR_BOUNDS;
+ } else {
+ mBoundsInfoMode &= ~BOUNDS_INFO_EDITOR_BOUNDS;
+ }
+ updateBoundsInfoMode();
+ });
+
+ final CheckBox visibleLineBoundsInfoCheckBox = new CheckBox(this);
+ visibleLineBoundsInfoCheckBox.setText("VisibleLineBounds");
+ visibleLineBoundsInfoCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ if (isChecked) {
+ mBoundsInfoMode |= BOUNDS_INFO_VISIBLE_LINE_BOUNDS;
+ } else {
+ mBoundsInfoMode &= ~BOUNDS_INFO_VISIBLE_LINE_BOUNDS;
+ }
+ updateBoundsInfoMode();
+ });
+
+ mBoundsInfoCheckBoxes.addView(editorBoundsInfoCheckBox);
+ mBoundsInfoCheckBoxes.addView(visibleLineBoundsInfoCheckBox);
+ return mBoundsInfoCheckBoxes;
+ }
+
private View getRichGestureGranularitySpinner() {
if (mRichGestureGranularitySpinner != null) {
return mRichGestureGranularitySpinner;
@@ -294,6 +358,7 @@ public class HandwritingIme extends InputMethodService {
Log.d(TAG, "onPrepareStylusHandwriting ");
if (mInk == null) {
mInk = new InkView(this, new HandwritingFinisherImpl(), new StylusConsumer());
+ mInk.setBoundsInfoMode(mBoundsInfoMode);
}
}
@@ -323,4 +388,16 @@ public class HandwritingIme extends InputMethodService {
private boolean areRichGesturesEnabled() {
return mRichGestureMode != OP_NONE;
}
+
+ @Override
+ public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+ if (mInk != null) {
+ mInk.setCursorAnchorInfo(cursorAnchorInfo);
+ }
+ }
+
+ @Override
+ public void onStartInput(EditorInfo attribute, boolean restarting) {
+ updateCursorAnchorInfo(mBoundsInfoMode);
+ }
}
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
index e94c79ecca00..86b324cf08d9 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
@@ -26,6 +26,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowMetrics;
+import android.view.inputmethod.CursorAnchorInfo;
class InkView extends View {
private static final long FINISH_TIMEOUT = 1500;
@@ -37,6 +38,9 @@ class InkView extends View {
private static final float STYLUS_MOVE_TOLERANCE = 1;
private Runnable mFinishRunnable;
+ private CursorAnchorInfo mCursorAnchorInfo;
+ private int mBoundsInfoMode;
+
InkView(Context context, HandwritingIme.HandwritingFinisher hwController,
HandwritingIme.StylusConsumer consumer) {
super(context);
@@ -66,6 +70,7 @@ class InkView extends View {
canvas.drawPath(mPath, mPaint);
canvas.drawARGB(20, 255, 50, 50);
+ BoundsInfoDrawHelper.draw(canvas, this, mBoundsInfoMode, mCursorAnchorInfo);
}
private void stylusStart(float x, float y) {
@@ -156,4 +161,15 @@ class InkView extends View {
return mFinishRunnable;
}
+ void setCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+ mCursorAnchorInfo = cursorAnchorInfo;
+ invalidate();
+ }
+
+ void setBoundsInfoMode(int boundsInfoMode) {
+ if (boundsInfoMode != mBoundsInfoMode) {
+ invalidate();
+ }
+ mBoundsInfoMode = boundsInfoMode;
+ }
}