PageRenderTime 57ms CodeModel.GetById 14ms app.highlight 9ms RepoModel.GetById 11ms app.codeStats 1ms

/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
 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}