1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.android.test.handwritingime;
18 
19 import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_EDITOR_BOUNDS;
20 import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_NONE;
21 import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_VISIBLE_LINE_BOUNDS;
22 
23 import android.graphics.Canvas;
24 import android.graphics.Color;
25 import android.graphics.Matrix;
26 import android.graphics.Paint;
27 import android.graphics.RectF;
28 import android.view.View;
29 import android.view.inputmethod.CursorAnchorInfo;
30 import android.view.inputmethod.EditorBoundsInfo;
31 
32 import androidx.annotation.Nullable;
33 
34 import com.android.internal.graphics.ColorUtils;
35 
36 import java.util.List;
37 
38 public class BoundsInfoDrawHelper {
39     private static final Paint sPaint = new Paint();
40     private static final int EDITOR_BOUNDS_COLOR =
41             ColorUtils.setAlphaComponent(Color.DKGRAY, 128);
42     private static final int HANDWRITING_BOUNDS_COLOR =
43             ColorUtils.setAlphaComponent(Color.BLUE, 128);
44     private static final int VISIBLE_LINE_BOUNDS_COLOR =
45             ColorUtils.setAlphaComponent(Color.MAGENTA, 128);
46 
draw(Canvas canvas, View inkView, int boundsInfoMode, CursorAnchorInfo cursorAnchorInfo)47     public static void draw(Canvas canvas, View inkView, int boundsInfoMode,
48             CursorAnchorInfo cursorAnchorInfo) {
49         if (boundsInfoMode == BOUNDS_INFO_NONE || cursorAnchorInfo == null) {
50             return;
51         }
52 
53         // The matrix in CursorAnchorInfo transforms the editor coordinates to on-screen
54         // coordinates. We then transform the matrix from the on-screen coordinates to the
55         // inkView's coordinates. So the result matrix transforms the editor coordinates
56         // to the inkView coordinates.
57         final Matrix matrix = cursorAnchorInfo.getMatrix();
58         inkView.transformMatrixToLocal(matrix);
59 
60         if ((boundsInfoMode & BOUNDS_INFO_EDITOR_BOUNDS) != 0) {
61             drawEditorBoundsInfo(canvas, matrix, cursorAnchorInfo.getEditorBoundsInfo());
62         }
63 
64         if ((boundsInfoMode & BOUNDS_INFO_VISIBLE_LINE_BOUNDS) != 0) {
65             drawVisibleLineBounds(canvas, matrix, cursorAnchorInfo.getVisibleLineBounds());
66         }
67     }
68 
setPaintForEditorBoundsInfo()69     private static void setPaintForEditorBoundsInfo() {
70         sPaint.reset();
71         sPaint.setStyle(Paint.Style.STROKE);
72         sPaint.setStrokeWidth(5f);
73     }
74 
drawEditorBoundsInfo(Canvas canvas, Matrix matrix, @Nullable EditorBoundsInfo editorBoundsInfo)75     private static void drawEditorBoundsInfo(Canvas canvas, Matrix matrix,
76             @Nullable EditorBoundsInfo editorBoundsInfo) {
77         if (editorBoundsInfo == null) {
78             return;
79         }
80         final RectF editorBounds = editorBoundsInfo.getEditorBounds();
81         setPaintForEditorBoundsInfo();
82         if (editorBounds != null) {
83             final RectF localEditorBounds = new RectF(editorBounds);
84             matrix.mapRect(localEditorBounds);
85             sPaint.setColor(EDITOR_BOUNDS_COLOR);
86             canvas.drawRect(localEditorBounds, sPaint);
87         }
88 
89         final RectF handwritingBounds = editorBoundsInfo.getHandwritingBounds();
90         if (handwritingBounds != null) {
91             final RectF localHandwritingBounds = new RectF(handwritingBounds);
92             matrix.mapRect(localHandwritingBounds);
93             sPaint.setColor(HANDWRITING_BOUNDS_COLOR);
94             canvas.drawRect(localHandwritingBounds, sPaint);
95         }
96     }
97 
setPaintForVisibleLineBounds()98     private static void setPaintForVisibleLineBounds() {
99         sPaint.reset();
100         sPaint.setStyle(Paint.Style.STROKE);
101         sPaint.setStrokeWidth(2f);
102         sPaint.setColor(VISIBLE_LINE_BOUNDS_COLOR);
103     }
104 
drawVisibleLineBounds(Canvas canvas, Matrix matrix, List<RectF> visibleLineBounds)105     private static void drawVisibleLineBounds(Canvas canvas, Matrix matrix,
106             List<RectF> visibleLineBounds) {
107         if (visibleLineBounds.isEmpty()) {
108             return;
109         }
110         setPaintForVisibleLineBounds();
111         for (RectF lineBound : visibleLineBounds) {
112             matrix.mapRect(lineBound);
113             canvas.drawRect(lineBound, sPaint);
114         }
115     }
116 }
117