Making Android Lint Theme Aware — Part 1

Over the last year or so, we have seen a lot of apps provide support for Dark Theme in their apps. Android Q brought this toggle to the system setting. Eventually, users will expect all apps to have/provide support for Dark theme and apps not doing so will be the exception rather than the norm.
In this post, I am not going to talk about how we can add dark theme support to our apps. For that we can consult my other post:
Through these series of posts, we’ll see how we can use Android Lint to quickly detect screens in our app which aren’t yet ready to support a dark theme variant. Using lint will also make our implementation future proof, as it will complain when a color is hardcoded in a layout/vector drawable file (used as #FFFFFF
instead of @color/white
) or a color resource has been added but it doesn’t contain a dark theme (night
qualifier) variant.
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
- Description — A short summary describing the problem rather than the fix
- Explanation — a full explanation of the issue, with suggestions for how to fix it
- Category — the associated category, if any
- Priority — the priority, a number from 1 to 10
- Severity — 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)

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.
In part 2, we will add another lint check that will warn about color resources that don’t have a corresponding dark theme (night
qualifier) variants. Follow me on Twitter or Medium to be notified when the next post is available. I’ll also update this post with a link to the next article.
Update: Read Part 2 Here:
Remember to appreciate (clap) the post if you learned something or it was helpful. The custom lint checks are available as a library for integration with your apps. More details on Github: https://github.com/saurabharora90/Lint-Checks