Android lint system provides a lot of helpful checks but it’s not exhaustive. It’s difficult to build all checks as they can vary as per user needs. Hence, Lint provides an API, to allow users to build their own checks. We’ll use this powerful capability to build two types of checks to help us with building and maintaining dark-theme:

Warn about hardcoded colors. If we want to add support for a dark theme in our apps, hardcoded colors in XML files (especially layout files), are a big no. (Part 1)

Warn about missing color resources in dark theme ( night qualifier) variants. (Part 2)

Brief Overview of Lint

A lint check is made up of four basic entities:

Issue: An issue is a problem in the source code. This is what comes up in the lint report files. Detector: A class which is used to detect issues/problems in the source code. Essentially this where the issue (problem) detection logic resides. A detector can report multiple issues. Implementation: Binds an issue with a detector class so that lint know where to look for a given issue. Registry: A list of all the list of checks to be performed on an Android project

Not let’s look at how we can detect hardcoded colors in our XML files. First, let’s set up a Java Library module which will house our lint checks and add a dependency to the lint API:

Issue

Next up, let’s define the issue that we are going to look for in the source code.

An issue is made up of:

Id — the fixed id of the issue

— the fixed id of the issue Description — A short summary describing the problem rather than the fix

— A short summary describing the problem rather than the fix Explanation — a full explanation of the issue, with suggestions for how to fix it

— a full explanation of the issue, with suggestions for how to fix it Category — the associated category, if any

— the associated category, if any Priority — the priority, a number from 1 to 10

— the priority, a number from 1 to 10 Severity — the default severity of the issue

— the default severity of the issue Implementation — the default implementation for this issue. We have already bonded this issue with a detector class.

Detector

Android Lint provides various detectors for us to use depending on the type of file we want to scan. Since we are looking for issues inside XML files, we’ll use the ResourceXmlDetector which defines how an XML file is parsed. It might help to understand the XML markup before proceeding. You can read about it here

Next, let’s define the attributes (such as background , foreground , textColor , tint , fillColor , etc) where we could have hardcoded colors directly instead of referencing them. Hardcoded colors are a big no when it comes to adding support for a dark theme. These will be the list of attributes that our detector declares that it wants to analyze.

visitAttribute is then called for each attribute that the detector has mentioned it wants to analyze. Here we check if the value of the attribute begins with a # (such as #FFFFFF ) and if it does, we report it as an issue that we had defined earlier. context.getLocation(attribute) gets the exact line number of the issue so that it can be pointed out the in HTML/XML report file that is generated at the end.

Note: The example above goes through all XML files (layouts, drawables, vector assets, etc.)

Registry

Finally, we will create a Registry of our lint checks and update the build.gradle so that Lint can pick it up when it runs.

Usage

To incorporate this newly created lint check in your app, update your app’s build.gradle file to include a dependency to the lint module:

dependencies { ....

lintChecks project(':dark-theme-lint')

}

Run the lint check as usual and you should see new lint errors appear in your project (if you have any hardcoded colors in your XML files)

Direct Color Use Lint Check on a sample project

Now we have a comprehensive list of places where a color value has been hardcoded. Once we have resolved these warnings by using color resources, this lint check will act as a deterrent for future developers being able to hardcode color values in layout/drawable files. By integrating lint checks with the CI system, this is one less thing us developers need to worry about in code reviews/PRs.