Commit 511b20bb authored by MozLando's avatar MozLando
Browse files

Merge #6112



6112: For #6102 : Add lint checks for using app namespace for vector drawables r=pocmo a=ekager
Co-authored-by: default avatarekager <ekager@mozilla.com>
parents c9e89d02 2712336d
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package mozilla.components.tooling.lint
import com.android.SdkConstants.ATTR_SRC
import com.android.SdkConstants.FQCN_IMAGE_BUTTON
import com.android.SdkConstants.FQCN_IMAGE_VIEW
import com.android.SdkConstants.IMAGE_BUTTON
import com.android.SdkConstants.IMAGE_VIEW
import com.android.annotations.VisibleForTesting
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.ResourceXmlDetector
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import org.w3c.dom.Element
/**
* A custom lint check that prohibits not using the app:srcCompat for ImageViews
*/
class AndroidSrcXmlDetector : ResourceXmlDetector() {
companion object {
const val SCHEMA = "http://schemas.android.com/apk/res/android"
const val FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON =
"androidx.appcompat.widget.AppCompatImageButton"
const val FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS =
"androidx.appcompat.widget.AppCompatImageView"
const val APP_COMPAT_IMAGE_BUTTON = "AppCompatImageButton"
const val APP_COMPAT_IMAGE_VIEW = "AppCompatImageView"
const val ERROR_MESSAGE = "Using android:src to define resource instead of app:srcCompat"
@VisibleForTesting
val ISSUE_XML_SRC_USAGE = Issue.create(
id = "AndroidSrcXmlDetector",
briefDescription = "Prohibits using android:src in ImageViews and ImageButtons",
explanation = "ImageView (and descendants) images should be declared using app:srcCompat",
category = Category.CORRECTNESS,
severity = Severity.ERROR,
implementation = Implementation(
AndroidSrcXmlDetector::class.java,
Scope.RESOURCE_FILE_SCOPE
)
)
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
// Return true if we want to analyze resource files in the specified resource
// folder type. In this case we only need to analyze layout resource files.
return folderType == ResourceFolderType.LAYOUT
}
override fun getApplicableElements(): Collection<String>? {
return setOf(
FQCN_IMAGE_VIEW,
IMAGE_VIEW,
FQCN_IMAGE_BUTTON,
IMAGE_BUTTON,
FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON,
FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS,
APP_COMPAT_IMAGE_BUTTON,
APP_COMPAT_IMAGE_VIEW
)
}
override fun visitElement(context: XmlContext, element: Element) {
if (!element.hasAttributeNS(SCHEMA, ATTR_SRC)) return
val node = element.getAttributeNodeNS(SCHEMA, ATTR_SRC)
context.report(
issue = ISSUE_XML_SRC_USAGE,
scope = node,
location = context.getLocation(node),
message = ERROR_MESSAGE
)
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package mozilla.components.tooling.lint
import com.android.SdkConstants.ATTR_TINT
import com.android.SdkConstants.FQCN_IMAGE_BUTTON
import com.android.SdkConstants.FQCN_IMAGE_VIEW
import com.android.SdkConstants.IMAGE_BUTTON
import com.android.SdkConstants.IMAGE_VIEW
import com.android.annotations.VisibleForTesting
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.ResourceXmlDetector
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import org.w3c.dom.Element
/**
* A custom lint check that prohibits not using the app:tint for ImageViews
*/
class ImageViewAndroidTintXmlDetector : ResourceXmlDetector() {
companion object {
const val SCHEMA = "http://schemas.android.com/apk/res/android"
const val FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON =
"androidx.appcompat.widget.AppCompatImageButton"
const val FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS =
"androidx.appcompat.widget.AppCompatImageView"
const val APP_COMPAT_IMAGE_BUTTON = "AppCompatImageButton"
const val APP_COMPAT_IMAGE_VIEW = "AppCompatImageView"
const val ERROR_MESSAGE =
"Using android:tint to tint ImageView instead of app:tint with AppCompatImageView"
@VisibleForTesting
val ISSUE_XML_SRC_USAGE = Issue.create(
id = "AndroidSrcXmlDetector",
briefDescription = "Prohibits using android:tint in ImageViews and ImageButtons",
explanation = "ImageView (and descendants) should be tinted using app:tint",
category = Category.CORRECTNESS,
severity = Severity.ERROR,
implementation = Implementation(
ImageViewAndroidTintXmlDetector::class.java,
Scope.RESOURCE_FILE_SCOPE
)
)
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
// Return true if we want to analyze resource files in the specified resource
// folder type. In this case we only need to analyze layout resource files.
return folderType == ResourceFolderType.LAYOUT
}
override fun getApplicableElements(): Collection<String>? {
return setOf(
FQCN_IMAGE_VIEW,
IMAGE_VIEW,
FQCN_IMAGE_BUTTON,
IMAGE_BUTTON,
FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON,
FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS,
APP_COMPAT_IMAGE_BUTTON,
APP_COMPAT_IMAGE_VIEW
)
}
override fun visitElement(context: XmlContext, element: Element) {
if (!element.hasAttributeNS(SCHEMA, ATTR_TINT)) return
val node = element.getAttributeNodeNS(SCHEMA, ATTR_TINT)
context.report(
issue = ISSUE_XML_SRC_USAGE,
scope = node,
location = context.getLocation(node),
message = ERROR_MESSAGE
)
}
}
......@@ -13,5 +13,10 @@ import com.android.tools.lint.detector.api.Issue
@Suppress("unused")
class LintIssueRegistry : IssueRegistry() {
override val api: Int = com.android.tools.lint.detector.api.CURRENT_API
override val issues: List<Issue> = LintLogChecks.issues
override val issues: List<Issue> = listOf(
LintLogChecks.ISSUE_LOG_USAGE,
AndroidSrcXmlDetector.ISSUE_XML_SRC_USAGE,
TextViewAndroidSrcXmlDetector.ISSUE_XML_SRC_USAGE,
ImageViewAndroidTintXmlDetector.ISSUE_XML_SRC_USAGE
)
}
......@@ -55,9 +55,5 @@ class LintLogChecks : Detector(), Detector.UastScanner {
Severity.WARNING,
Implementation(LintLogChecks::class.java, EnumSet.of(Scope.JAVA_FILE))
)
val issues: List<Issue> = listOf(
ISSUE_LOG_USAGE
)
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package mozilla.components.tooling.lint
import com.android.SdkConstants.ATTR_DRAWABLE_BOTTOM
import com.android.SdkConstants.ATTR_DRAWABLE_END
import com.android.SdkConstants.ATTR_DRAWABLE_LEFT
import com.android.SdkConstants.ATTR_DRAWABLE_RIGHT
import com.android.SdkConstants.ATTR_DRAWABLE_START
import com.android.SdkConstants.ATTR_DRAWABLE_TOP
import com.android.SdkConstants.FQCN_TEXT_VIEW
import com.android.SdkConstants.TEXT_VIEW
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.ResourceXmlDetector
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import org.w3c.dom.Element
/**
* A custom lint check that prohibits not using the app:srcCompat for ImageViews
*/
class TextViewAndroidSrcXmlDetector : ResourceXmlDetector() {
companion object {
const val SCHEMA = "http://schemas.android.com/apk/res/android"
const val ERROR_MESSAGE =
"Using android:drawableX to define resource instead of app:drawableXCompat"
val ISSUE_XML_SRC_USAGE = Issue.create(
id = "TextViewAndroidSrcXmlDetector",
briefDescription = "Prohibits using android namespace to define drawables in TextViews",
explanation = "TextView drawables should be declared using app:drawableXCompat",
category = Category.CORRECTNESS,
severity = Severity.ERROR,
implementation = Implementation(
TextViewAndroidSrcXmlDetector::class.java,
Scope.RESOURCE_FILE_SCOPE
)
)
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
// Return true if we want to analyze resource files in the specified resource
// folder type. In this case we only need to analyze layout resource files.
return folderType == ResourceFolderType.LAYOUT
}
override fun getApplicableElements(): Collection<String>? {
return setOf(
FQCN_TEXT_VIEW,
TEXT_VIEW
)
}
override fun visitElement(context: XmlContext, element: Element) {
val node = when {
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_BOTTOM) -> element.getAttributeNodeNS(
SCHEMA,
ATTR_DRAWABLE_BOTTOM
)
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_END) -> element.getAttributeNodeNS(
SCHEMA,
ATTR_DRAWABLE_END
)
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_LEFT) -> element.getAttributeNodeNS(
SCHEMA,
ATTR_DRAWABLE_LEFT
)
element.hasAttributeNS(
SCHEMA,
ATTR_DRAWABLE_RIGHT
) -> element.getAttributeNodeNS(SCHEMA, ATTR_DRAWABLE_RIGHT)
element.hasAttributeNS(
SCHEMA,
ATTR_DRAWABLE_START
) -> element.getAttributeNodeNS(SCHEMA, ATTR_DRAWABLE_START)
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_TOP) -> element.getAttributeNodeNS(
SCHEMA,
ATTR_DRAWABLE_TOP
)
else -> null
} ?: return
context.report(
issue = ISSUE_XML_SRC_USAGE,
scope = node,
location = context.getLocation(node),
message = ERROR_MESSAGE
)
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package mozilla.components.tooling.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
* Tests for the [AndroidSrcXmlDetector] custom lint check.
*/
@RunWith(JUnit4::class)
class AndroidSrcXmlDetectorTest : LintDetectorTest() {
override fun getIssues(): MutableList<Issue> =
mutableListOf(AndroidSrcXmlDetector.ISSUE_XML_SRC_USAGE)
override fun getDetector(): Detector = AndroidSrcXmlDetector()
@Test
fun expectPass() {
lint()
.files(
xml(
"res/layout/layout.xml", """
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
"""
)
).allowMissingSdk(true)
.run()
.expectClean()
}
@Test
fun expectFail() {
lint()
.files(
xml(
"res/layout/layout.xml", """
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_close"
/>
"""
)
).allowMissingSdk(true)
.run()
.expect(
"""
res/layout/layout.xml:5: Error: Using android:src to define resource instead of app:srcCompat [AndroidSrcXmlDetector]
android:src="@drawable/ic_close"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
"""
)
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package mozilla.components.tooling.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
* Tests for the [ImageViewAndroidTintXmlDetector] custom lint check.
*/
@RunWith(JUnit4::class)
class ImageViewAndroidTintXmlDetectorTest : LintDetectorTest() {
override fun getIssues(): MutableList<Issue> =
mutableListOf(ImageViewAndroidTintXmlDetector.ISSUE_XML_SRC_USAGE)
override fun getDetector(): Detector = ImageViewAndroidTintXmlDetector()
@Test
fun expectPass() {
lint()
.files(
xml(
"res/layout/layout.xml", """
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
"""
)
).allowMissingSdk(true)
.run()
.expectClean()
}
@Test
fun expectFail() {
lint()
.files(
xml(
"res/layout/layout.xml", """
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_close"
android:tint="@color/photonBlue90"
/>
"""
)
).allowMissingSdk(true)
.run()
.expect(
"""
res/layout/layout.xml:6: Error: Using android:tint to tint ImageView instead of app:tint with AppCompatImageView [AndroidSrcXmlDetector]
android:tint="@color/photonBlue90"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
"""
)
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package mozilla.components.tooling.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/**
* Tests for the [TextViewAndroidSrcXmlDetector] custom lint check.
*/
@RunWith(JUnit4::class)
class TextViewAndroidSrcXmlDetectorTest : LintDetectorTest() {
override fun getIssues(): MutableList<Issue> =
mutableListOf(TextViewAndroidSrcXmlDetector.ISSUE_XML_SRC_USAGE)
override fun getDetector(): Detector = TextViewAndroidSrcXmlDetector()
@Test
fun expectPass() {
lint()
.files(
xml(
"res/layout/layout.xml", """
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
"""
)
).allowMissingSdk(true)
.run()
.expectClean()
}
@Test
fun expectFail() {
lint()
.files(
xml(
"res/layout/layout.xml", """
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_close"
/>
"""
)
).allowMissingSdk(true)
.run()
.expect(
"""
res/layout/layout.xml:5: Error: Using android:drawableX to define resource instead of app:drawableXCompat [TextViewAndroidSrcXmlDetector]
android:drawableStart="@drawable/ic_close"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
"""
)
}
}
......@@ -2,8 +2,8 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="1dp">
......@@ -11,13 +11,12 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:gravity="start|center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:drawableStart="@drawable/mozac_ic_extensions_black"
android:drawablePadding="8dp"
android:text="@string/mozac_add_on_install_progress_caption"/>
android:gravity="start|center_vertical"
android:padding="16dp"
android:text="@string/mozac_add_on_install_progress_caption"
app:drawableStartCompat="@drawable/mozac_ic_extensions_black" />
</androidx.cardview.widget.CardView>
......@@ -6,6 +6,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="80dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#272727"
tools:ignore="Overdraw"
android:gravity="center_vertical"
......@@ -49,7 +50,7 @@
android:layout_width="22dp"
android:layout_height="22dp"
android:padding="4dp"
android:src="@drawable/mozac_ic_info"
app:srcCompat="@drawable/mozac_ic_info"
android:background="?android:attr/selectableItemBackgroundBorderless" />
</LinearLayout>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment