diff options
author | Tor Norbye <tnorbye@google.com> | 2011-12-19 17:06:27 -0800 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-12-19 17:10:11 -0800 |
commit | 76d1bf760b373427be686b7d925b9b35abb526d2 (patch) | |
tree | 0221917b61cf8adfcc4435a78bec47cfac54691c | |
parent | 3d73211da767ae07698d12db1f6d6f8a0b0ed7bd (diff) | |
download | sdk-76d1bf760b373427be686b7d925b9b35abb526d2.zip sdk-76d1bf760b373427be686b7d925b9b35abb526d2.tar.gz sdk-76d1bf760b373427be686b7d925b9b35abb526d2.tar.bz2 |
Fix Lint false positive for mixed XML/PNG Bitmap resource
This changeset fixes this issue:
http://code.google.com/p/android/issues/detail?id=23214
The icon detector makes sure that if an icon appears in a given -dpi
folder, it appears in all the other -dpi folders as well (except for
-nodpi). However, in the set comparison it would use the full filename
(including file extension), which is not correct since it's okay to
have an .9.png in one folder and a .gif in another (and as reported in
this bug, an .xml file).
This changeset also associates a file location with folder warnings
for a missing density folder (it uses the res folder), which made
various unit tests need updates since the results sort differently.
Change-Id: I7f09772f3a54683a9d0c5c5d93ae2499707f533a
5 files changed, 141 insertions, 14 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java index 7ca3fab..0392a6f 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java @@ -179,7 +179,7 @@ class DefaultSdkInfo extends SdkInfo { PARENTS.put("MultiAutoCompleteTextView", //$NON-NLS-1$ "AutoCompleteTextView"); //$NON-NLS-1$ - assert PARENTS.size() == CLASS_COUNT; + assert PARENTS.size() == CLASS_COUNT : PARENTS.size(); /* // Check that all widgets lead to the root view diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java index 186a5f3..4dbcbb3 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java @@ -115,6 +115,21 @@ public class LintUtils { } /** + * Returns the basename of the given filename, unless it's a dot-file such as ".svn". + * + * @param fileName the file name to extract the basename from + * @return the basename (the filename without the file extension) + */ + public static String getBaseName(String fileName) { + int extension = fileName.indexOf('.'); + if (extension > 0) { + return fileName.substring(0, extension); + } else { + return fileName; + } + } + + /** * Returns the children elements of the given node * * @param node the parent node diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java index 5f7adcb..56941bb 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java @@ -44,7 +44,6 @@ import com.android.tools.lint.detector.api.Scope; import com.android.tools.lint.detector.api.Severity; import com.android.tools.lint.detector.api.Speed; import com.android.tools.lint.detector.api.XmlContext; -import com.google.common.collect.Sets; import com.google.common.io.Files; import org.w3c.dom.Element; @@ -300,7 +299,7 @@ public class IconDetector extends Detector implements Detector.XmlScanner { Set<String> names = new HashSet<String>(files.length); for (File f : files) { String name = f.getName(); - if (hasBitmapExtension(name)) { + if (isDrawableFile(name)) { names.add(f.getName()); } } @@ -325,9 +324,10 @@ public class IconDetector extends Detector implements Detector.XmlScanner { } } - private static boolean hasBitmapExtension(String name) { + private static boolean isDrawableFile(String name) { // endsWith(name, DOT_PNG) is also true for endsWith(name, DOT_9PNG) - return endsWith(name, DOT_PNG)|| endsWith(name, DOT_JPG) || endsWith(name, DOT_GIF); + return endsWith(name, DOT_PNG)|| endsWith(name, DOT_JPG) || endsWith(name, DOT_GIF) || + endsWith(name, DOT_XML); } // This method looks for duplicates in the assets. This uses two pieces of information @@ -740,7 +740,7 @@ public class IconDetector extends Detector implements Detector.XmlScanner { if (missing.size() > 0 ) { context.report( ICON_MISSING_FOLDER, - null /* location */, + Location.create(res), String.format("Missing density variation folders in %1$s: %2$s", context.getProject().getDisplayPath(res), LintUtils.formatList(missing, missing.size())), @@ -764,7 +764,7 @@ public class IconDetector extends Detector implements Detector.XmlScanner { String folderName = folder.getName(); if (!isNoDpiFolder(folder)) { assert DENSITY_PATTERN.matcher(folderName).matches(); - Set<String> overlap = Sets.intersection(noDpiNames, entry.getValue()); + Set<String> overlap = nameIntersection(noDpiNames, entry.getValue()); inBoth.addAll(overlap); for (String name : overlap) { files.add(new File(folder, name)); @@ -811,8 +811,10 @@ public class IconDetector extends Detector implements Detector.XmlScanner { } Set<String> names = entry.getValue(); if (names.size() != allNames.size()) { - List<String> delta = - new ArrayList<String>(Sets.difference(allNames, names)); + List<String> delta = new ArrayList<String>(nameDifferences(allNames, names)); + if (delta.size() == 0) { + continue; + } Collections.sort(delta); String foundIn = ""; if (delta.size() == 1) { @@ -842,6 +844,81 @@ public class IconDetector extends Detector implements Detector.XmlScanner { } } + /** + * Compute the difference in names between a and b. This is not just + * Sets.difference(a, b) because we want to make the comparisons <b>without + * file extensions</b> and return the result <b>with</b>.. + */ + private Set<String> nameDifferences(Set<String> a, Set<String> b) { + Set<String> names1 = new HashSet<String>(a.size()); + for (String s : a) { + names1.add(LintUtils.getBaseName(s)); + } + Set<String> names2 = new HashSet<String>(b.size()); + for (String s : b) { + names2.add(LintUtils.getBaseName(s)); + } + + names1.removeAll(names2); + + if (names1.size() > 0) { + // Map filenames back to original filenames with extensions + Set<String> result = new HashSet<String>(names1.size()); + for (String s : a) { + if (names1.contains(LintUtils.getBaseName(s))) { + result.add(s); + } + } + for (String s : b) { + if (names1.contains(LintUtils.getBaseName(s))) { + result.add(s); + } + } + + return result; + } + + return Collections.emptySet(); + } + + /** + * Compute the intersection in names between a and b. This is not just + * Sets.intersection(a, b) because we want to make the comparisons <b>without + * file extensions</b> and return the result <b>with</b>. + */ + private Set<String> nameIntersection(Set<String> a, Set<String> b) { + Set<String> names1 = new HashSet<String>(a.size()); + for (String s : a) { + names1.add(LintUtils.getBaseName(s)); + } + Set<String> names2 = new HashSet<String>(b.size()); + for (String s : b) { + names2.add(LintUtils.getBaseName(s)); + } + + names1.retainAll(names2); + + if (names1.size() > 0) { + // Map filenames back to original filenames with extensions + Set<String> result = new HashSet<String>(names1.size()); + for (String s : a) { + if (names1.contains(LintUtils.getBaseName(s))) { + result.add(s); + } + } + for (String s : b) { + if (names1.contains(LintUtils.getBaseName(s))) { + result.add(s); + } + } + + return result; + } + + + return Collections.emptySet(); + } + private static boolean isNoDpiFolder(File file) { return file.getName().contains("-nodpi"); } diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/IconDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/IconDetectorTest.java index 7c105ad..d6da23d 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/IconDetectorTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/IconDetectorTest.java @@ -27,11 +27,12 @@ public class IconDetectorTest extends AbstractCheckTest { public void test() throws Exception { assertEquals( - "Warning: Missing density variation folders in res: drawable-xhdpi\n" + "drawable-hdpi: Warning: Missing the following drawables in drawable-hdpi: sample_icon.gif (found in drawable-mdpi)\n" + "drawable/ic_launcher.png: Warning: The ic_launcher.png icon has identical contents in the following configuration folders: drawable-mdpi, drawable\n" + "ic_launcher.png: Warning: Found bitmap drawable res/drawable/ic_launcher.png in densityless folder\n" + + "res: Warning: Missing density variation folders in res: drawable-xhdpi\n" + "sample_icon.gif: Warning: Using the .gif format for bitmaps is discouraged", + lintProject( "res/drawable/ic_launcher.png", "res/drawable/ic_launcher.png=>res/drawable-mdpi/ic_launcher.png", @@ -44,9 +45,10 @@ public class IconDetectorTest extends AbstractCheckTest { public void test2() throws Exception { assertEquals( - "Warning: Missing density variation folders in res: drawable-mdpi, drawable-xhdpi\n" + "drawable-hdpi/other.9.png: Warning: The following unrelated icon files have identical contents: appwidget_bg.9.png, other.9.png\n" + - "drawable-hdpi/unrelated.png: Warning: The following unrelated icon files have identical contents: ic_launcher.png, unrelated.png", + "drawable-hdpi/unrelated.png: Warning: The following unrelated icon files have identical contents: ic_launcher.png, unrelated.png\n" + + "res: Warning: Missing density variation folders in res: drawable-mdpi, drawable-xhdpi", + lintProject( "res/drawable-hdpi/unrelated.png", "res/drawable-hdpi/appwidget_bg.9.png", @@ -58,9 +60,10 @@ public class IconDetectorTest extends AbstractCheckTest { public void testNoDpi() throws Exception { assertEquals( - "Warning: Missing density variation folders in res: drawable-hdpi, drawable-xhdpi\n" + "drawable-xlarge-nodpi-v11/frame.png: Warning: The frame.png icon has identical contents in the following configuration folders: drawable-mdpi, drawable-nodpi, drawable-xlarge-nodpi-v11\n" + - "frame.png: Warning: The following images appear in both -nodpi and in a density folder: frame.png", + "frame.png: Warning: The following images appear in both -nodpi and in a density folder: frame.png\n" + + "res: Warning: Missing density variation folders in res: drawable-hdpi, drawable-xhdpi", + lintProject( "res/drawable-mdpi/frame.png", "res/drawable-nodpi/frame.png", @@ -81,4 +84,30 @@ public class IconDetectorTest extends AbstractCheckTest { "res/drawable-mdpi/frame.png=>res/drawable-nodpi/file1.png", "res/drawable-mdpi/frame.png=>res/drawable-nodpi/file2.png")); } + + public void testNoDpiMix() throws Exception { + assertEquals( + "drawable-mdpi/frame.xml: Warning: The following images appear in both -nodpi and in a density folder: frame.png, frame.xml\n" + + "res: Warning: Missing density variation folders in res: drawable-hdpi, drawable-xhdpi", + + lintProject( + "res/drawable-mdpi/frame.png", + "res/drawable/states.xml=>res/drawable-nodpi/frame.xml")); + } + + + public void testMixedFormat() throws Exception { + // Test having a mixture of .xml and .png resources for the same name + // Make sure we don't get: + // drawable-hdpi: Warning: Missing the following drawables in drawable-hdpi: f.png (found in drawable-mdpi) + // drawable-xhdpi: Warning: Missing the following drawables in drawable-xhdpi: f.png (found in drawable-mdpi) + assertEquals( + "No warnings.", + + lintProject( + "res/drawable-mdpi/frame.png=>res/drawable-mdpi/f.png", + "res/drawable/states.xml=>res/drawable-hdpi/f.xml", + "res/drawable/states.xml=>res/drawable-xhdpi/f.xml")); + } + }
\ No newline at end of file diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java index ba3df3b..6f585b0 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java @@ -46,6 +46,12 @@ public class LintUtilsTest extends TestCase { assertFalse(LintUtils.isXmlFile(new File("xml.png"))); } + public void testGetBasename() throws Exception { + assertEquals("foo", LintUtils.getBaseName("foo.png")); + assertEquals("foo", LintUtils.getBaseName("foo.9.png")); + assertEquals(".foo", LintUtils.getBaseName(".foo")); + } + public void testEditDistance() { assertEquals(0, LintUtils.editDistance("kitten", "kitten")); |