1 /* 2 * Copyright (C) 2017 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 package com.example.android.autofill.app; 17 18 import android.app.assist.AssistStructure; 19 import android.app.assist.AssistStructure.ViewNode; 20 import android.app.assist.AssistStructure.WindowNode; 21 import android.os.Bundle; 22 import android.util.Log; 23 import android.view.View; 24 import android.view.ViewStructure.HtmlInfo; 25 import android.view.autofill.AutofillValue; 26 27 import java.util.Arrays; 28 import java.util.Set; 29 30 public final class Util { 31 32 public static final String TAG = "AutofillSample"; 33 public static final boolean DEBUG = true; 34 public static final boolean VERBOSE = false; 35 public static final String EXTRA_DATASET_NAME = "dataset_name"; 36 public static final String EXTRA_FOR_RESPONSE = "for_response"; 37 bundleToString(StringBuilder builder, Bundle data)38 private static void bundleToString(StringBuilder builder, Bundle data) { 39 final Set<String> keySet = data.keySet(); 40 builder.append("[Bundle with ").append(keySet.size()).append(" keys:"); 41 for (String key : keySet) { 42 builder.append(' ').append(key).append('='); 43 Object value = data.get(key); 44 if ((value instanceof Bundle)) { 45 bundleToString(builder, (Bundle) value); 46 } else { 47 builder.append((value instanceof Object[]) 48 ? Arrays.toString((Object[]) value) : value); 49 } 50 } 51 builder.append(']'); 52 } 53 bundleToString(Bundle data)54 public static String bundleToString(Bundle data) { 55 if (data == null) { 56 return "N/A"; 57 } 58 final StringBuilder builder = new StringBuilder(); 59 bundleToString(builder, data); 60 return builder.toString(); 61 } 62 getAutofillTypeAsString(int type)63 public static String getAutofillTypeAsString(int type) { 64 switch (type) { 65 case View.AUTOFILL_TYPE_TEXT: 66 return "TYPE_TEXT"; 67 case View.AUTOFILL_TYPE_LIST: 68 return "TYPE_LIST"; 69 case View.AUTOFILL_TYPE_NONE: 70 return "TYPE_NONE"; 71 case View.AUTOFILL_TYPE_TOGGLE: 72 return "TYPE_TOGGLE"; 73 case View.AUTOFILL_TYPE_DATE: 74 return "TYPE_DATE"; 75 } 76 return "UNKNOWN_TYPE"; 77 } 78 getAutofillValueAndTypeAsString(AutofillValue value)79 private static String getAutofillValueAndTypeAsString(AutofillValue value) { 80 if (value == null) return "null"; 81 82 StringBuilder builder = new StringBuilder(value.toString()).append('('); 83 if (value.isText()) { 84 builder.append("isText"); 85 } else if (value.isDate()) { 86 builder.append("isDate"); 87 } else if (value.isToggle()) { 88 builder.append("isToggle"); 89 } else if (value.isList()) { 90 builder.append("isList"); 91 } 92 return builder.append(')').toString(); 93 } 94 dumpStructure(AssistStructure structure)95 public static void dumpStructure(AssistStructure structure) { 96 int nodeCount = structure.getWindowNodeCount(); 97 Log.v(TAG, "dumpStructure(): component=" + structure.getActivityComponent() 98 + " numberNodes=" + nodeCount); 99 for (int i = 0; i < nodeCount; i++) { 100 Log.v(TAG, "node #" + i); 101 WindowNode node = structure.getWindowNodeAt(i); 102 dumpNode(" ", node.getRootViewNode()); 103 } 104 } 105 dumpNode(String prefix, ViewNode node)106 private static void dumpNode(String prefix, ViewNode node) { 107 StringBuilder builder = new StringBuilder(); 108 builder.append(prefix) 109 .append("autoFillId: ").append(node.getAutofillId()) 110 .append("\tidEntry: ").append(node.getIdEntry()) 111 .append("\tid: ").append(node.getId()) 112 .append("\tclassName: ").append(node.getClassName()) 113 .append('\n'); 114 115 builder.append(prefix) 116 .append("focused: ").append(node.isFocused()) 117 .append("\tvisibility").append(node.getVisibility()) 118 .append("\tchecked: ").append(node.isChecked()) 119 .append("\twebDomain: ").append(node.getWebDomain()) 120 .append("\thint: ").append(node.getHint()) 121 .append('\n'); 122 123 HtmlInfo htmlInfo = node.getHtmlInfo(); 124 125 if (htmlInfo != null) { 126 builder.append(prefix) 127 .append("HTML TAG: ").append(htmlInfo.getTag()) 128 .append(" attrs: ").append(htmlInfo.getAttributes()) 129 .append('\n'); 130 } 131 132 String[] afHints = node.getAutofillHints(); 133 CharSequence[] options = node.getAutofillOptions(); 134 builder.append(prefix).append("afType: ").append(getAutofillTypeAsString(node.getAutofillType())) 135 .append("\tafValue:") 136 .append(getAutofillValueAndTypeAsString(node.getAutofillValue())) 137 .append("\tafOptions:").append(options == null ? "N/A" : Arrays.toString(options)) 138 .append("\tafHints: ").append(afHints == null ? "N/A" : Arrays.toString(afHints)) 139 .append("\tinputType:").append(node.getInputType()) 140 .append('\n'); 141 142 int numberChildren = node.getChildCount(); 143 builder.append(prefix).append("# children: ").append(numberChildren) 144 .append("\ttext: ").append(node.getText()) 145 .append('\n'); 146 147 Log.v(TAG, builder.toString()); 148 final String prefix2 = prefix + " "; 149 for (int i = 0; i < numberChildren; i++) { 150 Log.v(TAG, prefix + "child #" + i); 151 dumpNode(prefix2, node.getChildAt(i)); 152 } 153 } 154 }