The DayNight functionality in AppCompat allows your app to easily switch between a dark ⚫ and light ⚪ theme. This has many benefits for your users, from saving power on OLED displays, to increasing usability for people with reduced-vision, and more.

How do I use it?

You need to change your theme to extend from one of the DayNight variants, and then call one method to enable the feature. Here’s an example theme declaration:

<style name="MyTheme" parent="Theme.AppCompat.DayNight"> <!-- Blah blah --> </style>

If you’re using Material Design Components (and I recommend you to do so), then you can also use the Theme.MaterialComponents.DayNight theme from their v1.1.0 release. The rest of this post remains the same.

You then need to enable the feature in your app using one of the APIs provided.

setDefaultNightMode

The first API we provide to do that is AppCompatDelegate.setDefaultNightMode() , which takes one of the follow values:

MODE_NIGHT_NO . Always use the day (light) theme.

. Always use the day (light) theme. MODE_NIGHT_YES . Always use the night (dark) theme.

. Always use the night (dark) theme. MODE_NIGHT_FOLLOW_SYSTEM (default). This setting follows the system’s setting, which on Android Q and above is a system setting (more on this below).

(default). This setting follows the system’s setting, which on Android Q and above is a system setting (more on this below). MODE_NIGHT_AUTO_BATTERY . Changes to dark when the device has its ‘Battery Saver’ feature enabled, light otherwise.

✨ New in v1.1.0-alpha03.

. Changes to dark when the device has its ‘Battery Saver’ feature enabled, light otherwise. ✨ MODE_NIGHT_AUTO_TIME & MODE_NIGHT_AUTO . Changes between day/night based on the time of day.

⛔ Deprecated in v1.1.0-alpha03.

The method is static so you can call it at any time. The value you set is not persisted across process starts though, therefore you need to set it every time your app process is started. I recommend setting it in your application class (if you have one) like so:

public class MyApplication extends Application {



public void onCreate() {

super.onCreate(); AppCompatDelegate.setDefaultNightMode(

AppCompatDelegate.MODE_NIGHT_YES);

}

}

From AppCompat v1.1.0-alpha05 onwards, setDefaultNightMode() will automatically apply any DayNight changes to any ‘started’ Activities. This means that you no longer have to manually recreate any Activities when you call the API.

setLocalNightMode

You can also override the default value in each component with a call to its AppCompatDelegate’s setLocalNightMode() . This is handy when you know that only some components should use the DayNight functionality, or for development so that you don’t have to sit and wait for night to fall to test your layout.

Using this method in every Activity is now an anti-pattern, and you should move to using setDefaultNightMode() instead. See the section below for the technical details to why.

Activity recreations

Both of the methods mentioned above will recreate your Activity if a Configuration change is required, so that the new theme can be applied. This is a good opportunity to test whether your Activity + Fragments save their instance state correctly.

How can I check what configuration I’m currently in?

You can do this by checking your resource configuration:

int currentNightMode = getResources().getConfiguration().uiMode

& Configuration.UI_MODE_NIGHT_MASK

case Configuration.

// Night mode is not active, we're in day time

case Configuration.

// Night mode is active, we're at night!

case Configuration.

// We don't know what mode we're in, assume notnight

} switch (currentNightMode) {case Configuration. UI_MODE_NIGHT_NO // Night mode is not active, we're in day timecase Configuration. UI_MODE_NIGHT_ YES:// Night mode is active, we're at night!case Configuration. UI_MODE_NIGHT_ UNDEFINED:// We don't know what mode we're in, assume notnight

WebViews

There is currently one big caveat to using this feature: WebViews. Since they can not use theme attributes, and you rarely have control over any web content’s styling, there is a high probability that your WebViews will be too contrasting against your dynamic themed app. So make sure you test your app in both modes to ensure that it’s not annoying to the user.

System night mode

Android Q onwards has a system night mode which can be enabled in the Settings app. Android Pie also has a system night mode setting, but it is only surfaced in the device’s ‘developer options’. For ease, I recommend treating Android Pie the same as previous versions of Android.

In-app setting

It is recommended to provide a way for the user to override the default theme in your app. The recommended options and strings are:

‘Light’ ( MODE_NIGHT_NO )

) ‘Dark’ ( MODE_NIGHT_YES )

) ‘Set by Battery Saver’ ( MODE_NIGHT_AUTO_BATTERY ).

Only show on Android Pie and below. This should be your app’s default when shown.

). Only show on Android Pie and below. This should be your app’s default when shown. ‘Use system default’ ( MODE_NIGHT_FOLLOW_SYSTEM ).

Only show on Android Q and above. This should be your app’s default when shown.

A common way to do to implement would be via a ListPreference, calling to setDefaultNightMode() when the value changes.

Updating your themes + styles

As well as calling AppCompat, you will likely need to do some work to update your themes, styles and layouts so that they work seamlessly across both dark and light themes.

The rule-of-thumb for these things is to always use theme attributes when you can. Here are the most important to know about:

?android:attr/textColorPrimary . General purpose text color. Will be near-black on light theme, near-white on dark themes. Contains a disabled state.

. General purpose text color. Will be near-black on light theme, near-white on dark themes. Contains a disabled state. ?attr/colorControlNormal . General-purpose icon color. Contains a disabled state.

Using Material Design Components also makes this a lot easier, as it’s attributes (such as ?attr/colorSurface and ?attr/colorOnSurface ) provide you an easy generalized themed color to use. These attributes of course can be customized in your theme.

Using your own resources for dark/light

AppCompat in simple terms is just enabling the use of the night and notnight resource qualifiers. These have actually been available in the platform since API 8, but were previously only used in very specific scenarios.

Under the hood Theme.AppCompat.DayNight is implemented as so:

res/values/themes.xml

<style name="Theme.AppCompat.DayNight"

parent="Theme.AppCompat.Light" />

res/values-night/themes.xml

<style name="Theme.AppCompat.DayNight"

parent="Theme.AppCompat" />