/talkback_preics/src/com/google/android/marvin/talkback/formatter/WebContentFormatter.java
http://eyes-free.googlecode.com/ · Java · 190 lines · 107 code · 25 blank · 58 comment · 7 complexity · 12fb8a21c1695a16585bd0873298aeb1 MD5 · raw file
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.google.android.marvin.talkback.formatter;
- import com.google.android.marvin.talkback.Formatter;
- import com.google.android.marvin.talkback.R;
- import com.google.android.marvin.talkback.Utils;
- import com.google.android.marvin.talkback.Utterance;
- import org.xml.sax.SAXException;
- import android.content.Context;
- import android.text.TextUtils;
- import android.util.Xml;
- import android.view.accessibility.AccessibilityEvent;
- import java.util.regex.Pattern;
- /**
- * Formatter for web content.
- *
- * @author svetoslavganov@google.com (Svetoslav Ganov)
- * @author credo@google.com (Tim Credo)
- */
- @SuppressWarnings("unused")
- public final class WebContentFormatter implements Formatter {
-
- private static final int ACTION_SET_CURRENT_AXIS = 0;
- private static final int ACTION_TRAVERSE_CURRENT_AXIS = 1;
- private static final int ACTION_TRAVERSE_GIVEN_AXIS = 2;
- private static final int ACTION_PERFORM_AXIS_TRANSITION = 3;
- private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4;
- private static String[] sAxisNames;
- /**
- * A template to apply to markup before sending it to an XML parser.
- */
- private static final String XML_TEMPLATE =
- "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><div>%s</div>";
- /**
- * Regular expression that matches all HTML tags.
- */
- private final Pattern mStripMarkupPattern = Pattern.compile("<(.)+?>");
-
- /**
- * Regular expression that matches all entity codes.
- */
- private final Pattern mStripEntitiesPattern = Pattern.compile("&(.)+?;");
-
- /**
- * Regular expression that matches all div or span tags.
- */
- private final Pattern mStripDivSpanPattern = Pattern.compile(
- "</?(div|span).*?>", Pattern.CASE_INSENSITIVE);
- /**
- * Regular expression that matches some common singleton tags.
- */
- private final Pattern mCloseTagPattern = Pattern.compile(
- "(<(img|input|br).+?)>", Pattern.CASE_INSENSITIVE);
- /**
- * A handler for processing HTML and generating output for speaking.
- */
- private WebContentHandler mHtmlHandler = null;
-
-
- private final Action mTempAction = new Action();
- @Override
- public void format(AccessibilityEvent event, Context context, Utterance utterance,
- Object args) {
- // for now ... lookup and announce axis transitions
- CharSequence contentDescription = event.getContentDescription();
- if (TextUtils.isEmpty(contentDescription)) {
- return;
- }
- Action action = mTempAction;
- action.init(contentDescription.toString());
- int actionCode = mTempAction.mActionCode;
- if (actionCode == ACTION_PERFORM_AXIS_TRANSITION) {
- String axisAnnouncement = getAxisAnnouncement(context, action.mSecondArgument);
- utterance.getText().append(axisAnnouncement);
- return;
- }
- // for now ... disregard content description
- String markup = Utils.getEventText(context, event).toString();
- String noTags = mStripMarkupPattern.matcher(markup).replaceAll("");
- String cleaned = cleanMarkup(markup);
- if (mHtmlHandler == null) {
- mHtmlHandler = new TalkBackWebContentHandler(context.getResources());
- }
- try {
- Xml.parse(cleaned, mHtmlHandler);
- String speech = mHtmlHandler.getOutput();
- utterance.getText().append(speech);
- } catch (SAXException e) {
- e.printStackTrace();
- utterance.getText().append(noTags);
- }
- }
-
- /**
- * Process HTML to remove markup that can't be handled by the SAX parser.
- *
- * @param markup Input HTML generated by system.
- * @return A string of cleaned HTML.
- */
- public String cleanMarkup(String markup) {
- String noDivOrSpan = mStripDivSpanPattern.matcher(markup).replaceAll("");
- String noEntities = mStripEntitiesPattern.matcher(noDivOrSpan).replaceAll(" ");
- String tagsClosed = mCloseTagPattern.matcher(noEntities).replaceAll("$1/>");
- return String.format(XML_TEMPLATE, tagsClosed);
- }
- /**
- * Gets an announcement for a navigation axis given its code.
- *
- * @param context Context for loading resources.
- * @param axisCode The code the the axis.
- * @return The axis announcement.
- */
- private String getAxisAnnouncement(Context context, int axisCode) {
- if (sAxisNames == null) {
- sAxisNames = new String[] {
- context.getString(R.string.axis_character),
- context.getString(R.string.axis_word),
- context.getString(R.string.axis_sentence),
- context.getString(R.string.axis_heading),
- context.getString(R.string.axis_sibling),
- context.getString(R.string.axis_parent_first_child),
- context.getString(R.string.axis_document),
- context.getString(R.string.axis_default_web_view_behavior)
- };
- }
- return sAxisNames[axisCode];
- }
- /**
- * Represents an action.
- */
- private class Action {
- private static final int ACTION_OFFSET = 24;
- private static final int ACTION_MASK = 0xFF000000;
- private static final int FIRST_ARGUMENT_OFFSET = 16;
- private static final int FIRST_ARGUMENT_MASK = 0x00FF0000;
- private static final int SECOND_ARGUMENT_OFFSET = 8;
- private static final int SECOND_ARGUMENT_MASK = 0x0000FF00;
- private static final int THIRD_ARGUMENT_OFFSET = 0;
- private static final int THIRD_ARGUMENT_MASK = 0x000000FF;
- private int mActionCode;
- private int mFirstArgument;
- private int mSecondArgument;
- private int mThirdArgument;
- public void init(String encodedActionString) {
- int encodedAction = 0;
- try {
- // hack
- encodedAction = Integer.decode("0x" + encodedActionString);
- } catch (NumberFormatException nfe) {
- return;
- }
- mActionCode = (encodedAction & ACTION_MASK) >> ACTION_OFFSET;
- mFirstArgument = (encodedAction & FIRST_ARGUMENT_MASK) >> FIRST_ARGUMENT_OFFSET;
- mSecondArgument = (encodedAction & SECOND_ARGUMENT_MASK) >> SECOND_ARGUMENT_OFFSET;
- mThirdArgument = (encodedAction & THIRD_ARGUMENT_OFFSET) >> THIRD_ARGUMENT_MASK;
- }
- }
- }