/TalkBack/src/com/google/android/marvin/talkback/speechrules/NodeProcessor.java

http://eyes-free.googlecode.com/ · 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. package com.google.android.marvin.talkback.speechrules;
  17. import android.content.Context;
  18. import android.text.TextUtils;
  19. import android.view.accessibility.AccessibilityEvent;
  20. import android.view.accessibility.AccessibilityNodeInfo;
  21. import com.google.android.marvin.talkback.R;
  22. import com.google.android.marvin.talkback.Utterance;
  23. import java.util.LinkedList;
  24. /**
  25. * @author alanv@google.com (Alan Viverette)
  26. */
  27. public class NodeProcessor {
  28. private static final String DESCRIPTION_SEPARATOR = ". ";
  29. private final LinkedList<NodeSpeechRule> mRules = new LinkedList<NodeSpeechRule>();
  30. private final Context mContext;
  31. public NodeProcessor(Context context) {
  32. mContext = context;
  33. loadRules();
  34. }
  35. /**
  36. * Returns the best description for a node.
  37. *
  38. * @param node The node to describe.
  39. * @param event The source event, may be {@code null} when called with
  40. * non-source nodes.
  41. * @return The best description for a node.
  42. */
  43. public CharSequence process(AccessibilityNodeInfo node, AccessibilityEvent event) {
  44. final StringBuilder populator = new StringBuilder();
  45. // Append the control's checked state.
  46. if (node.isCheckable()) {
  47. if (node.isChecked()) {
  48. appendTextToBuilder(mContext.getString(R.string.value_checked), populator);
  49. } else {
  50. appendTextToBuilder(mContext.getString(R.string.value_not_checked), populator);
  51. }
  52. }
  53. // Add node text
  54. final CharSequence text = processWithRules(node, event);
  55. if (!TextUtils.isEmpty(text)) {
  56. appendTextToBuilder(text, populator);
  57. }
  58. if (TextUtils.isEmpty(populator)) {
  59. return null;
  60. }
  61. // Append the control's disabled state.
  62. if (!node.isEnabled()) {
  63. appendTextToBuilder(mContext.getString(R.string.value_disabled), populator);
  64. }
  65. return populator;
  66. }
  67. /**
  68. * Loads the default rule set.
  69. */
  70. private void loadRules() {
  71. mRules.add(new RuleImageView());
  72. mRules.add(new RuleEditText());
  73. mRules.add(new RuleSeekBar());
  74. mRules.add(new RuleSimpleTemplate(android.widget.Spinner.class, R.string.template_spinner));
  75. mRules.add(new RuleSimpleTemplate(android.webkit.WebView.class, R.string.value_web_view));
  76. // Always add the default rule last.
  77. mRules.add(new RuleDefault());
  78. }
  79. /**
  80. * Processes the specified node using a series of speech rules.
  81. *
  82. * @param node The node to process.
  83. * @param event The source event, may be {@code null} when called with
  84. * non-source nodes.
  85. * @return A string representing the given node, or {@code null} if the node
  86. * could not be processed.
  87. */
  88. private CharSequence processWithRules(AccessibilityNodeInfo node, AccessibilityEvent event) {
  89. for (NodeSpeechRule rule : mRules) {
  90. if (rule.accept(node)) {
  91. return rule.format(mContext, node, event);
  92. }
  93. }
  94. return null;
  95. }
  96. /**
  97. * Returns the verbose description for a node.
  98. *
  99. * @param node The node to describe.
  100. * @return The verbose description for a node.
  101. */
  102. public static CharSequence processVerbose(Context context, AccessibilityNodeInfo node) {
  103. // TODO(alanv): This method shouldn't be static. Or here at all?
  104. final StringBuilder populator = new StringBuilder();
  105. // Append control's interaction capabilities or disabled state
  106. if (node.isEnabled()) {
  107. if (node.isClickable()) {
  108. appendTextToBuilder(context.getString(R.string.value_clickable), populator);
  109. }
  110. if (node.isLongClickable()) {
  111. appendTextToBuilder(context.getString(R.string.value_long_clickable), populator);
  112. }
  113. }
  114. return populator;
  115. }
  116. /**
  117. * Helper for appending the given {@link String} to the existing text in an
  118. * {@link Utterance}. Also adds a punctuation separator.
  119. *
  120. * @param text {@link String} of text to append.
  121. * @param builder {@link StringBuilder} to which text is appended.
  122. */
  123. private static void appendTextToBuilder(CharSequence text, StringBuilder builder) {
  124. builder.append(text);
  125. builder.append(DESCRIPTION_SEPARATOR);
  126. }
  127. }