/AccessCheck/src/com/android/accessibility/AccessibilityValidator.java

http://eyes-free.googlecode.com/ · Java · 191 lines · 105 code · 17 blank · 69 comment · 14 complexity · 47cef111989a52b583da0180afb2b051 MD5 · raw file

  1. /*
  2. * Copyright 2010 Google Inc.
  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.android.accessibility;
  17. import org.xml.sax.InputSource;
  18. import org.xml.sax.SAXException;
  19. import org.xml.sax.XMLReader;
  20. import org.xml.sax.helpers.XMLReaderFactory;
  21. import java.io.*;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.logging.Logger;
  25. /**
  26. * An object that fetches all Android layout files and manages the testing of
  27. * the files with the use of the AccessibilityValidationContentHandler. This
  28. * object also reports on any errors encountered during the testing.
  29. *
  30. * @author dtseng@google.com (David Tseng)
  31. */
  32. public class AccessibilityValidator {
  33. /** The root path to scan for Android layout files. */
  34. private final File mRootFilePath;
  35. /** Errors generated by thrown exceptions (and not by validation errors). */
  36. private final List<String> mGeneralErrors = new ArrayList<String>();
  37. /** A list of files we wish to have tested. */
  38. private List<InputSource> mLayoutFiles;
  39. /** The total number of validation test errors across all files. */
  40. private int mTotalValidationErrors = 0;
  41. /** The path to the Android sdk jar. */
  42. private final File mAndroidSdkPath;
  43. /** The object that handles our logging. */
  44. private static final Logger sLogger = Logger.getLogger("android.accessibility");
  45. /**
  46. * The entry point to this tool.
  47. *
  48. * @param <args>
  49. * path on which to search for layout xml files that need
  50. * validation
  51. */
  52. public static void main(String[] args) {
  53. sLogger.info("AccessibilityValidator");
  54. if (args.length == 2) {
  55. sLogger.info("Validating classes using android jar for subclasses of ImageView");
  56. new AccessibilityValidator(args[0], args[1]).run();
  57. } else {
  58. sLogger.info("Usage: java AccessibilityValidator <path> <Android jar path>");
  59. return;
  60. }
  61. }
  62. /**
  63. * Constructs an AccessibilityValidator object using the root path and the
  64. * android jar path.
  65. */
  66. public AccessibilityValidator(String rootPath, String androidSdkPath) {
  67. mRootFilePath = new File(rootPath);
  68. mAndroidSdkPath = new File(androidSdkPath);
  69. if (!mRootFilePath.exists()) {
  70. throw new IllegalArgumentException("Invalid root path specified "
  71. + rootPath);
  72. } else if (!mAndroidSdkPath.exists()) {
  73. throw new IllegalArgumentException(
  74. "Invalid android sdk path specified " + androidSdkPath);
  75. }
  76. }
  77. /**
  78. * Performs validation of Android layout files and logs errors that have
  79. * been encountered during the validation. Returns true if the validation
  80. * passes.
  81. */
  82. private boolean run() {
  83. sLogger.info("Validating files under " + mRootFilePath);
  84. mLayoutFiles = findLayoutFiles(mRootFilePath);
  85. validateFiles();
  86. for (String error : mGeneralErrors) {
  87. sLogger.info(error);
  88. }
  89. sLogger.info("done with validation");
  90. return mGeneralErrors.size() == 0;
  91. }
  92. /**
  93. * Accumulates a list of files under the path that meet two constraints.
  94. * Firstly, it has a containing (parent) directory of "layout". Secondly, it
  95. * has an xml extension
  96. */
  97. private List<InputSource> findLayoutFiles(File directory) {
  98. List<InputSource> layoutFiles = new ArrayList<InputSource>();
  99. for (File file : directory.listFiles()) {
  100. // The file is a directory; recurse on the file.
  101. if (file.isDirectory()) {
  102. List<InputSource> directoryFiles = findLayoutFiles(file);
  103. layoutFiles.addAll(directoryFiles);
  104. // Does the containing directory and filename meet our
  105. // constraints?
  106. } else if (directory.getName().toLowerCase().contains("layout")
  107. && file.getName().toLowerCase().endsWith(".xml")) {
  108. InputSource addition;
  109. try {
  110. addition = new InputSource(new FileReader(file));
  111. // Store this explicitly for logging.
  112. addition.setPublicId(file.toString());
  113. layoutFiles.add(addition);
  114. } catch (FileNotFoundException fileNotFoundException) {
  115. mGeneralErrors.add("File not found "
  116. + fileNotFoundException);
  117. }
  118. }
  119. }
  120. return layoutFiles;
  121. }
  122. /*
  123. * Processes a list of files via an AccessibilityValidationContentHandler.
  124. * The caller will only be notified of errors via logging.
  125. */
  126. public void validateFiles() {
  127. sLogger.info("Validating " + getLayoutFiles().size());
  128. XMLReader reader;
  129. try {
  130. reader = XMLReaderFactory.createXMLReader();
  131. } catch (SAXException saxExp) {
  132. mGeneralErrors.add("Error " + saxExp);
  133. return;
  134. }
  135. for (InputSource file : getLayoutFiles()) {
  136. try {
  137. AccessibilityValidationContentHandler contentHandler
  138. = new AccessibilityValidationContentHandler(
  139. file.getPublicId(), mAndroidSdkPath);
  140. reader.setContentHandler(contentHandler);
  141. reader.parse(file);
  142. mTotalValidationErrors += contentHandler.getValidationErrors();
  143. } catch (IOException ioExp) {
  144. mGeneralErrors.add("Error reading file " + ioExp);
  145. } catch (SAXException saxExp) {
  146. mGeneralErrors.add("Error " + saxExp);
  147. }
  148. }
  149. }
  150. /**
  151. * Returns the number of general errors (considered caught exceptions).
  152. */
  153. public List<String> getGeneralErrors() {
  154. return mGeneralErrors;
  155. }
  156. /**
  157. * Sets the files to be tested.
  158. */
  159. public void setLayoutFiles(List<InputSource> layoutFiles) {
  160. this.mLayoutFiles = layoutFiles;
  161. }
  162. /**
  163. * Gets the files to be tested.
  164. */
  165. public List<InputSource> getLayoutFiles() {
  166. return mLayoutFiles;
  167. }
  168. /**
  169. * Gets the total number of test validation errors across all files.
  170. */
  171. public int getTotalValidationErrors() {
  172. return mTotalValidationErrors;
  173. }
  174. }