Lint detector for ColorStateLists that use app:alpha without android:alpha

Detection + quick fix + a new module for showing all available
AppCompat Lint rules

Bug: 146350188
Test: ./gradlew :lint-demos:lint-demo-appcompat:lint
Change-Id: I5def996beebe4d9f054044957eb4aaf1f7eb489e
diff --git a/appcompat/appcompat-lint/build.gradle b/appcompat/appcompat-lint/build.gradle
index e3e6bb0..d67f346 100644
--- a/appcompat/appcompat-lint/build.gradle
+++ b/appcompat/appcompat-lint/build.gradle
@@ -45,5 +45,5 @@
     mavenVersion = LibraryVersions.APPCOMPAT
     mavenGroup = LibraryGroups.APPCOMPAT
     inceptionYear = "2019"
-    description = "Appcompat Lint Checks"
+    description = "AppCompat Lint Checks"
 }
\ No newline at end of file
diff --git a/appcompat/appcompat-lint/src/main/java/androidx/appcompat/AppCompatIssueRegistry.kt b/appcompat/appcompat-lint/src/main/java/androidx/appcompat/AppCompatIssueRegistry.kt
index 0eb6076..db273d4 100644
--- a/appcompat/appcompat-lint/src/main/java/androidx/appcompat/AppCompatIssueRegistry.kt
+++ b/appcompat/appcompat-lint/src/main/java/androidx/appcompat/AppCompatIssueRegistry.kt
@@ -16,12 +16,13 @@
 
 package androidx.appcompat
 
+import androidx.appcompat.res.ColorStateListAlphaDetector
 import com.android.tools.lint.client.api.IssueRegistry
 import com.android.tools.lint.detector.api.CURRENT_API
 
 class AppCompatIssueRegistry : IssueRegistry() {
     override val api = CURRENT_API
     override val issues get() = listOf(
-        VanillaCheck.ISSUE
+        ColorStateListAlphaDetector.NOT_USING_ANDROID_ALPHA
     )
 }
diff --git a/appcompat/appcompat-lint/src/main/java/androidx/appcompat/VanillaCheck.kt b/appcompat/appcompat-lint/src/main/java/androidx/appcompat/VanillaCheck.kt
index 79575c2..2d35f41 100644
--- a/appcompat/appcompat-lint/src/main/java/androidx/appcompat/VanillaCheck.kt
+++ b/appcompat/appcompat-lint/src/main/java/androidx/appcompat/VanillaCheck.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
diff --git a/appcompat/appcompat-lint/src/main/java/androidx/appcompat/res/ColorStateListAlphaDetector.kt b/appcompat/appcompat-lint/src/main/java/androidx/appcompat/res/ColorStateListAlphaDetector.kt
new file mode 100644
index 0000000..9b7b7c0
--- /dev/null
+++ b/appcompat/appcompat-lint/src/main/java/androidx/appcompat/res/ColorStateListAlphaDetector.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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 androidx.appcompat.res
+
+import com.android.SdkConstants
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.LintFix
+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 com.android.tools.lint.detector.api.XmlScanner
+import org.w3c.dom.Element
+
+class ColorStateListAlphaDetector : Detector(), XmlScanner {
+    companion object {
+        internal val NOT_USING_ANDROID_ALPHA: Issue = Issue.create(
+            "UseAndroidAlpha",
+            "`android:alpha` attribute missing on ColorStateList",
+            "ColorStateList uses app:alpha without android:alpha",
+            Category.CORRECTNESS,
+            1,
+            Severity.ERROR,
+            Implementation(ColorStateListAlphaDetector::class.java, Scope.RESOURCE_FILE_SCOPE)
+        )
+    }
+
+    override fun getApplicableElements(): Collection<String>? = listOf("selector")
+
+    override fun visitElement(context: XmlContext, element: Element) {
+        val items = element.getElementsByTagName("item")
+        for (index in 0 until items.length) {
+            val item = items.item(index) as Element
+            // Only look at items that have android:color
+            if (!item.hasAttributeNS(SdkConstants.ANDROID_URI, "color")) {
+                continue
+            }
+            val hasAppAlphaAttr = item.hasAttributeNS(SdkConstants.AUTO_URI, "alpha")
+            val hasAndroidAlphaAttr = item.hasAttributeNS(SdkConstants.ANDROID_URI, "alpha")
+            if (hasAppAlphaAttr && !hasAndroidAlphaAttr) {
+                context.report(
+                    NOT_USING_ANDROID_ALPHA,
+                    item,
+                    context.getLocation(item),
+                    "Must use 'android:alpha' if 'app:alpha' is used.",
+                    LintFix.create().set(SdkConstants.ANDROID_URI, "alpha",
+                        item.getAttributeNS(SdkConstants.AUTO_URI, "alpha")).build()
+                )
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e814436..30df614 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
diff --git a/lint-demos/lint-demo-appcompat/OWNERS b/lint-demos/lint-demo-appcompat/OWNERS
new file mode 100644
index 0000000..71598a1
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
diff --git a/lint-demos/lint-demo-appcompat/build.gradle b/lint-demos/lint-demo-appcompat/build.gradle
new file mode 100644
index 0000000..9043a79
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/build.gradle
@@ -0,0 +1,25 @@
+import static androidx.build.dependencies.DependenciesKt.KOTLIN_STDLIB
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.application")
+    id("kotlin-android")
+}
+
+dependencies {
+    api 'com.google.android.material:material:1.0.0'
+    implementation(project(":appcompat:appcompat"))
+    implementation(project(":core:core"))
+    api(KOTLIN_STDLIB)
+}
+
+android {
+    defaultConfig {
+        vectorDrawables.useSupportLibrary = true
+    }
+    lintOptions {
+        disable "WrongThread"
+        // TODO: Enable lint after appcompat:1.1.0 release or use lint-baseline.xml instead.
+        abortOnError false
+    }
+}
diff --git a/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml b/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5459775
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/src/main/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.appcompat">
+    <application
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/app_sample_code"
+        android:label="@string/activity_sample_code"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AppCompat">
+
+        <activity android:name=".AppCompatLintDemo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/lint-demos/lint-demo-appcompat/src/main/java/com/example/android/appcompat/AppCompatLintDemo.java b/lint-demos/lint-demo-appcompat/src/main/java/com/example/android/appcompat/AppCompatLintDemo.java
new file mode 100644
index 0000000..fae81c3
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/src/main/java/com/example/android/appcompat/AppCompatLintDemo.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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.example.android.appcompat;
+
+import android.os.Bundle;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+/**
+ * Dummy activity for the AppCompat Lint demo
+ */
+public class AppCompatLintDemo extends AppCompatActivity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+}
diff --git a/lint-demos/lint-demo-appcompat/src/main/res/color/color_state_list_missing_android_alpha.xml b/lint-demos/lint-demo-appcompat/src/main/res/color/color_state_list_missing_android_alpha.xml
new file mode 100644
index 0000000..a1142a9
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/src/main/res/color/color_state_list_missing_android_alpha.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item app:alpha="?android:disabledAlpha"
+          android:color="?colorPrimary"
+          android:state_enabled="false"/>
+    <item android:color="?colorPrimary"/>
+</selector>
\ No newline at end of file
diff --git a/lint-demos/lint-demo-appcompat/src/main/res/drawable-hdpi/app_sample_code.png b/lint-demos/lint-demo-appcompat/src/main/res/drawable-hdpi/app_sample_code.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/src/main/res/drawable-hdpi/app_sample_code.png
Binary files differ
diff --git a/lint-demos/lint-demo-appcompat/src/main/res/values/strings.xml b/lint-demos/lint-demo-appcompat/src/main/res/values/strings.xml
new file mode 100644
index 0000000..fe0e95a
--- /dev/null
+++ b/lint-demos/lint-demo-appcompat/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<resources>
+    <string name="activity_sample_code">Lint Demo AppCompat</string>
+</resources>
diff --git a/settings.gradle b/settings.gradle
index d2ff5f2..7a80011 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -161,6 +161,7 @@
 includeProject(":lifecycle:lifecycle-viewmodel", "lifecycle/lifecycle-viewmodel")
 includeProject(":lifecycle:lifecycle-viewmodel-ktx", "lifecycle/lifecycle-viewmodel-ktx")
 includeProject(":lifecycle:lifecycle-viewmodel-savedstate","lifecycle/lifecycle-viewmodel-savedstate")
+includeProject(":lint-demos:lint-demo-appcompat", "lint-demos/lint-demo-appcompat")
 includeProject(":loader:loader", "loader/loader")
 includeProject(":loader:loader-ktx", "loader/loader-ktx")
 includeProject(":localbroadcastmanager:localbroadcastmanager", "localbroadcastmanager/localbroadcastmanager")