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