Google recently announced a feature of Android Q called Dark Theme. This setting allows users to apply a theme that will flip light colors to dark and vice-versa. Per Google's documentation, in addition to giving users the preference of a different look-and-feel, this theme has several benefits:

  • Reducing battery power usage
  • Improving usability for light-sensitive users
  • Increasing visibility for all users in low-light environments

The Dark Theme setting in the Android Q System Tray

It should be noted that Dark Theme is not completely new functionality in Android Q. Support was introduced for Day and Night themes with the release of the Android Support library version 23.2 in 2016. However, with Android Q Google has rebranded this functionality as Dark Theme and given it a greater emphasis with several enhancements.

  • A new tile allows users to switch in and out of the Dark Theme setting via the system tray
  • On Pixel devices running Android Q, the battery saver mode enables Dark Theme automatically
  • The implementation of the DayNight theme has been greatly improved in AppCompat v1.1.0, addressing several major bugs
  • A new setting, forceDarkEnabled, allows the Android operating system to automatically convert your application to a dark theme

Developers will need to make changes in order to provide an optimized user experience when Dark Theme is enabled. At I/O this year, Google strongly encouraged developers to enhance their applications to support Dark Theme going forward. Google has committed to supporting this theme for all of its applications by the time Android Q is launched, which will most likely be in late Q3 of this year.

How Can I Deliver a Great Dark Theme Experience?

When we learned about Dark Theme, we had several questions about how to optimize your application to support this new theme:

  • Do you have to target Android Q or will there be support libraries available that make Dark Theme backward compatible?
  • How effective is Android Q's forceDarkAllowed? Can this theme setting be enough to provide a good user experience?
  • How can you further optimize your application's components to better support dark theme?
  • What happens to icons? What about image content?
  • Lastly, how does dark theme treat WebViews?

Exploring DarkTheme

We set out to build a sample application that was purposely built with specific UI components that would help us answer some of these questions.

Sample application

Google outlines two approaches to supporting Dark Theme:

  1. If you have an existing application that does night extend a DayNight theme, set the forceDarkAllowed attribute in your theme to true and allow the Android Operating System to automatically convert your application to a Dark Theme (this only works on Android Q)
  2. Extending either the AppCompat.DayNight theme or the MaterialComponents.DayNight theme and implementing custom theme attributes where appropriate (recommended, especially for new apps)

We decided to explore the forceDarkEnabled option first. This would likely represent the most practical route for existing applications that do not extend a DayNight theme as it would not require significant rework to the existing theme.

In order to do so, we made sure our application's theme did not extend a DayNight theme (Android's forceDarkEnabled theme attribute will not take effect if you do so). The following is what our styles.xml looked like:

<resources>
 <style name="Theme.MyTheme" parent="@style/Theme.MaterialComponents.Light">
 <item name="colorPrimary">@color/colorPrimary</item>
 <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
 <item name="colorSecondary">@color/colorSecondary</item>
 <item name="colorAccent">@color/colorAccent</item>
 <item name="android:forceDarkAllowed">true</item>
 </style>
</resources>

Making sure that we extended AppCompatAcivity, our next step was to set the default night mode. We built a settings screen that allowed you to toggle between various night mode settings.

Dark Theme Settings

We also built a ThemeHelper class that we used to set the appropriate Dark Mode on launch (or any time you changed this setting).

fun applyTheme(themePref: String) {
 when (themePref) {
 LIGHT_MODE -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
 DARK_MODE -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
 DEFAULT_MODE -> {
 if (BuildCompat.isAtLeastQ()) {
 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
 } else {
 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
 }
 }
 }
}

When we ran our application and enabled Dark Theme in the System Tray, force dark was applied. In our opinion, the Android Operating System did well in flipping our application's colors.

Sample Application with Force Dark Enabled

Our WebView content was also automatically styled in a Dark Theme as well.

WebView with Force Dark Enabled

Further Optimizing for Dark Theme

While android:forceDarkAllowed provided a pretty good Dark Theme experience out-of-the-box, there were a few items that we believed could look even better.

  • The yellow floating action button looked kind of ugly
  • The chat text was a little too dark and somewhat difficult to read
  • The white outlines around the profile pictures were too bright and contrasty

We had the option to apply night-qualified resources to address these issues, but we wanted to follow Google's recommended approach to implementing a Dark Theme. So, we changed our application's theme to extend the AppCompat.DayNight and began creating our own fully custom night-qualified resources rather than relying on force dark.

Here's a snippet from our styles.xml:

<style name="Theme.MyApp" parent="Theme.AppCompat.DayNight">

From here, we created a colors.xml resource that we placed in the night-conditional values resource folder. We selected colors based on what we felt would be the optimal experience while running Dark Theme.

<resources>
 <!-- app palette -->
 <color name="colorPrimary">#0362af</color>
 <color name="colorPrimaryDark">#071f38</color>
 <color name="colorSecondary">#7e96aa</color>
 <color name="colorAccent">#ffed66</color>
 <color name="colorAccentImage">#FFEB3B</color>
 <color name="colorPrimaryText">#FFFFFF</color>
 <color name="colorSecondaryText">#BDBDBD</color>
</resources>

While using this method, you may need to provide alternate image resource assets for users running Dark Theme, especially for icons. Depending on how many image resources (and how many device densities your application supports) this could result in a significant increase in APK size. However, there is a very efficient way to handle this if you're using vector drawables.

We implemented one of our icon mage assets as a vector drawable, the check mark indicator for sent and received messages. Instead of providing an entirely new asset, we referenced a theme color as the vector drawable's fillColor which would automatically become styled when running Dark Theme.

<vector xmlns:android="http://schemas.android.com/apk/res/android"
 android:width="24dp"
 android:height="24dp"
 android:viewportWidth="24.0"
 android:viewportHeight="24.0">
 <path
 android:fillColor="?attr/colorSecondaryVariant"
 android:pathData="M18,7l-1.41,-1.41 -6.34,6.34 1.41,1.41L18,7zM22.24,5.59L11.66,16.17 7.48,12l-1.41,1.41L11.66,19l12,-12 -1.42,-1.41zM0.41,13.41L6,19l1.41,-1.41L1.83,12 0.41,13.41z"/>
</vector>

When we ran our application, as expected it looked even better than it did when leveraging Force Dark.

Custom DayNight Theme with Dark Theme Enabled

We did discover what appears to potentially be a major issue with extending a DayNight theme: our WebView content was not styled in a Dark Theme manner like it was when Force Dark was leveraged. This could potentially be a major issue for applications that leverage WebViews and warrants more exploration to see if there are any other options to theme WebView content when extending a DayNight theme.

Custom DayNight Theme WebView with Dark Theme Enabled

Google's recommendation is to modify your WebView with custom styling for Dark Theme. The prefers-color-scheme: dark @media query provides developers with a way to define custom styling for a Dark Theme similar to the way Android allows you to provide night-conditional resources.

Conclusion

Support for Dark Theme is going to be an important UI aspect moving forward on the Android platform.

Google has provided two different paths for handling Dark Theme. The first option is to leverage Google's Force Dark mode and is recommended for applications that do not extend a DayNight theme. This option will only work for users running Android Q, however, the Dark Theme feature is not very discoverable on versions of Android prior to Q. While we cannot cite any statistics on the volume of Dark Theme users on Android Q versus older versions of the Android Operating System, it is probably a safe assumption that most Dark Theme users will be running Android Q. While this option has been presented as a quick and easy shortcut for handling Dark Theme, we found that its capabilities are quite powerful and that this option could prove to be a viable option for long-term use.

The second option is to extend a DayNight theme and provide a customized experience for users who have enabled Dark Theme. This is Google's recommended approach to implementing a Dark Theme and will require involvement from developers and designers to define a new set of colors and image resources for Dark Theme users.

As Google adopts Dark Theme for all of its applications and makes it easier to discover and enable Dark Theme on Android Q, more and more users will begin to use this feature. This will create an elevated expectation that applications have been optimized for Dark Theme.

We look forward to using this feature and seeing more and more applications support a Dark Theme optimized experience on Android Q. Check out our sample app on GitHub here.

Authors

Chris has over 13 years of software development experience. He is based out of our Reston, VA office and has experience building native mobile applications, web applications and APIs.

Alan Shih is a Senior Software Engineer at CapTech based in the Washington, DC metro area. Alan has a passion for innovative technology such as IoT and mobile devices to solve challenging problems.