AssistVisualizer.java revision 70d8be7616a450e9b7ef09c8bda5a8b25936a29a
1/*
2 * Copyright (C) 2015 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
17package com.android.test.voiceinteraction;
18
19import android.annotation.Nullable;
20import android.app.assist.AssistStructure;
21import android.content.Context;
22import android.graphics.Canvas;
23import android.graphics.Matrix;
24import android.graphics.Paint;
25import android.graphics.Rect;
26import android.util.AttributeSet;
27import android.util.Log;
28import android.view.View;
29
30import java.util.ArrayList;
31
32public class AssistVisualizer extends View {
33    static final String TAG = "AssistVisualizer";
34
35    static class TextEntry {
36        final Rect bounds;
37        final int parentLeft, parentTop;
38        final Matrix matrix;
39        final String className;
40        final CharSequence text;
41
42        TextEntry(AssistStructure.ViewNode node, int parentLeft, int parentTop, Matrix matrix) {
43            int left = parentLeft+node.getLeft();
44            int top = parentTop+node.getTop();
45            bounds = new Rect(left, top, left+node.getWidth(), top+node.getHeight());
46            this.parentLeft = parentLeft;
47            this.parentTop = parentTop;
48            this.matrix = new Matrix(matrix);
49            this.className = node.getClassName();
50            this.text = node.getText() != null ? node.getText() : node.getContentDescription();
51        }
52    }
53
54    AssistStructure mAssistStructure;
55    final Paint mFramePaint = new Paint();
56    final Paint mFrameNoTransformPaint = new Paint();
57    final ArrayList<Matrix> mMatrixStack = new ArrayList<>();
58    final ArrayList<TextEntry> mTextRects = new ArrayList<>();
59    final int[] mTmpLocation = new int[2];
60    final float[] mTmpMatrixPoint = new float[2];
61
62    public AssistVisualizer(Context context, @Nullable AttributeSet attrs) {
63        super(context, attrs);
64        setWillNotDraw(false);
65        mFramePaint.setColor(0xffff0000);
66        mFramePaint.setStyle(Paint.Style.STROKE);
67        mFramePaint.setStrokeWidth(0);
68        float density = getResources().getDisplayMetrics().density;
69        mFramePaint.setShadowLayer(density, density, density, 0xff000000);
70        mFrameNoTransformPaint.setColor(0xff0000ff);
71        mFrameNoTransformPaint.setStyle(Paint.Style.STROKE);
72        mFrameNoTransformPaint.setStrokeWidth(0);
73        mFrameNoTransformPaint.setShadowLayer(density, density, density, 0xff000000);
74    }
75
76    public void setAssistStructure(AssistStructure as) {
77        mAssistStructure = as;
78        mTextRects.clear();
79        final int N = as.getWindowNodeCount();
80        if (N > 0) {
81            for (int i=0; i<N; i++) {
82                AssistStructure.WindowNode windowNode = as.getWindowNodeAt(i);
83                mMatrixStack.clear();
84                Matrix matrix = new Matrix();
85                matrix.setTranslate(windowNode.getLeft(), windowNode.getTop());
86                mMatrixStack.add(matrix);
87                buildTextRects(windowNode.getRootViewNode(), 0, windowNode.getLeft(),
88                        windowNode.getTop());
89            }
90        }
91        Log.d(TAG, "Building text rects in " + this + ": found " + mTextRects.size());
92        invalidate();
93    }
94
95    public void logTree() {
96        if (mAssistStructure != null) {
97            mAssistStructure.dump();
98        }
99    }
100
101    public void logText() {
102        final int N = mTextRects.size();
103        for (int i=0; i<N; i++) {
104            TextEntry te = mTextRects.get(i);
105            Log.d(TAG, "View " + te.className + " " + te.bounds.toShortString()
106                    + " in " + te.parentLeft + "," + te.parentTop
107                    + " matrix=" + te.matrix.toShortString() + ": "
108                    + te.text);
109        }
110    }
111
112    public void clearAssistData() {
113        mAssistStructure = null;
114        mTextRects.clear();
115    }
116
117    void buildTextRects(AssistStructure.ViewNode root, int matrixStackIndex,
118            int parentLeft, int parentTop) {
119        if (root.getVisibility() != View.VISIBLE) {
120            return;
121        }
122        Matrix parentMatrix = mMatrixStack.get(matrixStackIndex);
123        matrixStackIndex++;
124        Matrix matrix;
125        if (mMatrixStack.size() > matrixStackIndex) {
126            matrix = mMatrixStack.get(matrixStackIndex);
127            matrix.set(parentMatrix);
128        } else {
129            matrix = new Matrix(parentMatrix);
130            mMatrixStack.add(matrix);
131        }
132        matrix.preTranslate(root.getLeft(), root.getTop());
133        int left = parentLeft + root.getLeft();
134        int top = parentTop + root.getTop();
135        Matrix transform = root.getTransformation();
136        if (transform != null) {
137            matrix.preConcat(transform);
138        }
139        if (root.getText() != null || root.getContentDescription() != null) {
140            TextEntry te = new TextEntry(root, parentLeft, parentTop, matrix);
141            mTextRects.add(te);
142        }
143        final int N = root.getChildCount();
144        if (N > 0) {
145            left -= root.getScrollX();
146            top -= root.getScrollY();
147            matrix.preTranslate(-root.getScrollX(), -root.getScrollY());
148            for (int i=0; i<N; i++) {
149                AssistStructure.ViewNode child = root.getChildAt(i);
150                buildTextRects(child, matrixStackIndex, left, top);
151            }
152        }
153    }
154
155    @Override
156    protected void onDraw(Canvas canvas) {
157        super.onDraw(canvas);
158        getLocationOnScreen(mTmpLocation);
159        final int N = mTextRects.size();
160        Log.d(TAG, "Drawing text rects in " + this + ": found " + mTextRects.size());
161        for (int i=0; i<N; i++) {
162            TextEntry te = mTextRects.get(i);
163            canvas.drawRect(te.bounds.left - mTmpLocation[0], te.bounds.top - mTmpLocation[1],
164                    te.bounds.right - mTmpLocation[0], te.bounds.bottom - mTmpLocation[1],
165                    mFrameNoTransformPaint);
166        }
167        for (int i=0; i<N; i++) {
168            TextEntry te = mTextRects.get(i);
169            canvas.save();
170            canvas.translate(-mTmpLocation[0], -mTmpLocation[1]);
171            canvas.concat(te.matrix);
172            canvas.drawRect(0, 0, te.bounds.right - te.bounds.left, te.bounds.bottom - te.bounds.top,
173                    mFramePaint);
174            canvas.restore();
175        }
176    }
177}
178