/TalkBack/src/com/google/android/marvin/talkback/speechrules/NodeProcessor.java
Java | 152 lines | 70 code | 25 blank | 57 comment | 11 complexity | 5e2ccaea2ca734dd13742add232df385 MD5 | raw file
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.google.android.marvin.talkback.speechrules; 18 19import android.content.Context; 20import android.text.TextUtils; 21import android.view.accessibility.AccessibilityEvent; 22import android.view.accessibility.AccessibilityNodeInfo; 23 24import com.google.android.marvin.talkback.R; 25import com.google.android.marvin.talkback.Utterance; 26 27import java.util.LinkedList; 28 29/** 30 * @author alanv@google.com (Alan Viverette) 31 */ 32public class NodeProcessor { 33 private static final String DESCRIPTION_SEPARATOR = ". "; 34 35 private final LinkedList<NodeSpeechRule> mRules = new LinkedList<NodeSpeechRule>(); 36 private final Context mContext; 37 38 public NodeProcessor(Context context) { 39 mContext = context; 40 41 loadRules(); 42 } 43 44 /** 45 * Returns the best description for a node. 46 * 47 * @param node The node to describe. 48 * @param event The source event, may be {@code null} when called with 49 * non-source nodes. 50 * @return The best description for a node. 51 */ 52 public CharSequence process(AccessibilityNodeInfo node, AccessibilityEvent event) { 53 final StringBuilder populator = new StringBuilder(); 54 55 // Append the control's checked state. 56 if (node.isCheckable()) { 57 if (node.isChecked()) { 58 appendTextToBuilder(mContext.getString(R.string.value_checked), populator); 59 } else { 60 appendTextToBuilder(mContext.getString(R.string.value_not_checked), populator); 61 } 62 } 63 64 // Add node text 65 final CharSequence text = processWithRules(node, event); 66 67 if (!TextUtils.isEmpty(text)) { 68 appendTextToBuilder(text, populator); 69 } 70 71 if (TextUtils.isEmpty(populator)) { 72 return null; 73 } 74 75 // Append the control's disabled state. 76 if (!node.isEnabled()) { 77 appendTextToBuilder(mContext.getString(R.string.value_disabled), populator); 78 } 79 80 return populator; 81 } 82 83 /** 84 * Loads the default rule set. 85 */ 86 private void loadRules() { 87 mRules.add(new RuleImageView()); 88 mRules.add(new RuleEditText()); 89 mRules.add(new RuleSeekBar()); 90 mRules.add(new RuleSimpleTemplate(android.widget.Spinner.class, R.string.template_spinner)); 91 mRules.add(new RuleSimpleTemplate(android.webkit.WebView.class, R.string.value_web_view)); 92 93 // Always add the default rule last. 94 mRules.add(new RuleDefault()); 95 } 96 97 /** 98 * Processes the specified node using a series of speech rules. 99 * 100 * @param node The node to process. 101 * @param event The source event, may be {@code null} when called with 102 * non-source nodes. 103 * @return A string representing the given node, or {@code null} if the node 104 * could not be processed. 105 */ 106 private CharSequence processWithRules(AccessibilityNodeInfo node, AccessibilityEvent event) { 107 for (NodeSpeechRule rule : mRules) { 108 if (rule.accept(node)) { 109 return rule.format(mContext, node, event); 110 } 111 } 112 113 return null; 114 } 115 116 /** 117 * Returns the verbose description for a node. 118 * 119 * @param node The node to describe. 120 * @return The verbose description for a node. 121 */ 122 public static CharSequence processVerbose(Context context, AccessibilityNodeInfo node) { 123 // TODO(alanv): This method shouldn't be static. Or here at all? 124 125 final StringBuilder populator = new StringBuilder(); 126 127 // Append control's interaction capabilities or disabled state 128 if (node.isEnabled()) { 129 if (node.isClickable()) { 130 appendTextToBuilder(context.getString(R.string.value_clickable), populator); 131 } 132 133 if (node.isLongClickable()) { 134 appendTextToBuilder(context.getString(R.string.value_long_clickable), populator); 135 } 136 } 137 138 return populator; 139 } 140 141 /** 142 * Helper for appending the given {@link String} to the existing text in an 143 * {@link Utterance}. Also adds a punctuation separator. 144 * 145 * @param text {@link String} of text to append. 146 * @param builder {@link StringBuilder} to which text is appended. 147 */ 148 private static void appendTextToBuilder(CharSequence text, StringBuilder builder) { 149 builder.append(text); 150 builder.append(DESCRIPTION_SEPARATOR); 151 } 152}