How to enable night mode programmatically?

59.1k Views Asked by At

I am looking for a way to enable night mode programmatically with an Android code:

public static void setNightMode(Context target, boolean state){

    UiModeManager uiManager = (UiModeManager) target.getSystemService(Context.UI_MODE_SERVICE);

    if (state) {
        //uiManager.enableCarMode(0);
        uiManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
    } else {
        // uiManager.disableCarMode(0);
        uiManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
    }
}

Nothing has changed on my screen, the night mode is still disables. According to this link

There is no need to enable carMode or deskMode. I have the following logcat on Android Studio:

11-26 12:15:16.662 3823-3823/? D/UiModeManager: updateConfigurationLocked: mDockState=0; mCarMode=false; mNightMode=2; uiMode=33
11-26 12:15:26.802 3823-3823/? V/UiModeManager: updateLocked: null action, mDockState=0, category=null
7

There are 7 best solutions below

5
On BEST ANSWER

SIMPLEST SOLUTION

You can enable/disable application's dark theme just by:

  1. enable dark theme:

     AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
    
  2. forcefully disable dark theme:

     AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
    
  3. set app theme based on mobile settings of dark mode, i.e. if dark mode is enabled then the theme will be set to a dark theme, if not then the default theme, but this will only work in version >= Android version Q (10)

     AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
    

Notes:

  1. Your base theme for app/activity should be

"Theme.AppCompat.DayNight"

like

<style name="DarkTheme" parent="Theme.AppCompat.DayNight">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>
  1. Your res folder's names would end with -night so that different colors and images you can set for day and night themes like

drawable & drawable-night,
values & values-night

1
On

Remember that Dark Mode is not Night Mode. They are completely different. DM was introduce in Android 10 that enforce built-in black and white color while NM was release in earlier version that uses either default/custom style commonly called as Resource Qualifiers. If you want to handle your own custom light/night style and not relying on Android's built-in dark style, you may want to set forceDarkAllowed to false in themes.xml or style.xml to avoid conflict.

To change your app mode to night you can do something like this

Application class onCreate

   val isAppNight = sharedPref.prefInt(DAY_NIGHT_THEME)

    // This will be the top level handling of theme
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        // If you don't want to adapt the device's theme settings, uncomment the snippet below
        /*uiModeManager.setApplicationNightMode(
            when (isAppNight) {
                DAY_THEME -> UiModeManager.MODE_NIGHT_NO // User set this explicitly
                NIGHT_THEME -> UiModeManager.MODE_NIGHT_YES // User set this explicitly
                else -> UiModeManager.MODE_NIGHT_AUTO // Follow the device Dark Theme settings when not define yet by user
            }
        )*/
    } else {

        AppCompatDelegate.setDefaultNightMode(
            when (isAppNight) {
                DAY_THEME -> AppCompatDelegate.MODE_NIGHT_NO // User set this explicitly
                NIGHT_THEME -> AppCompatDelegate.MODE_NIGHT_YES // User set this explicitly
                else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM // For Android 10 and 11, follow the device Dark Theme settings when not define yet by user
            }
        )

    }

Switch component

   // Update Light/Night mode status
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
       uiModeManager.setApplicationNightMode(
           when (item.isChecked) {
               true -> UiModeManager.MODE_NIGHT_YES
               else -> UiModeManager.MODE_NIGHT_NO
           }
        )
   } else {
        AppCompatDelegate.setDefaultNightMode(
            when (item.isChecked) {
                true -> AppCompatDelegate.MODE_NIGHT_YES
                else -> AppCompatDelegate.MODE_NIGHT_NO
             }
         )
   }

   // Save settings configuration in SharedPreferences
   sharedPref.prefInt(
       DAY_NIGHT_THEME,
       if (item.isChecked)
           NIGHT_THEME
       else
           DAY_THEME
   )

Here we are using SharedPreference for storing and updating the preferred theme of user. You may also need to use Theme.Material3.DayNight as your parent theme.

0
On

One more thing: your Activity needs to extend from AppCompatActivity.

If it extends the plain Activity, then calling AppCompatDelegate.setDefaultNightMode will not work.

0
On

This code is working perfectly for me, though you may just need to restart your app. But keep in mind, that this code enables the Dark Mode system-wide, not just in the app:

public static void setNightMode(Context target , boolean state){

    UiModeManager uiManager = (UiModeManager) target.getSystemService(Context.UI_MODE_SERVICE);

    if (VERSION.SDK_INT <= 22) {
        uiManager.enableCarMode(0);
    }
    
    if (state) {
        uiManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
    } else {
        uiManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
    }
}

This worked for me in Kitkat.

1
On
int nightModeFlags =
getContext().getResources().getConfiguration().uiMode &
Configuration.UI_MODE_NIGHT_MASK;
switch (nightModeFlags) {
case Configuration.UI_MODE_NIGHT_YES:
     doStuff();
     break;

case Configuration.UI_MODE_NIGHT_NO:
     doStuff();
     break;

case Configuration.UI_MODE_NIGHT_UNDEFINED:
     doStuff();
     break;
}
1
On

NightOwl has its own implementation for switching day/night mode on Android. Getting started with NightOwl is super easy. Here's a code snippet:

Init the NightOwl in Application class,

NightOwl.builder().defaultMode(0).create();

Call three method in your Activity class,

public class DemoActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // step1 before super.onCreate
        NightOwl.owlBeforeCreate(this);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        // step2 after setContentView
        NightOwl.owlAfterCreate(this);

        // write your code
    }

    @Override
    protected void onResume() {
        super.onResume();

        // step3 onResume
        NightOwl.owlResume(this);
    }

}

Switch skin everywhere as you like,

View v = findViewById(R.id.button);
v.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        NightOwl.owlNewDress(SettingActivity.this);
    }
});
1
On

Make sure to change the default theme from Theme.AppCompat.Light.DarkActionBar to Theme.AppCompat.DayNight.DarkActionBar in the styles.xml file and then do AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) to switch to the night mode. I have tested it in APIv23(Android 6.0) and above and it is working fine. For a better explanation see this codelab by Android