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