Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Edge-to-edge doesn't work when activity recreated or AppCompatDelegate.setDefaultNightMode() applied

I have this code for enabling edge-to-edge in my BaseActivity.kt class

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Log.d(Const.TAG_ACTIVITY, String.format("%s BaseActivity onCreate()", this.javaClass.simpleName))
    enableEdgeToEdge()
    initBinding()
    onActivityCreate(savedInstanceState)
    observeLiveData()
}

And this code for enabling insets listeners for applying correct padding to the views

override fun onActivityCreate(savedInstanceState: Bundle?) {
    InsetsManager.applyBottomNavigationViewInsets(bind.bottomNavContainer)
    InsetsManager.applyTutorialInsets(bind.tutorial, bind.promotionsTutorial)
}

Here is the code of InsetsManager.kt

object InsetsManager {

fun applyBottomNavigationViewInsets(bottomContainerView: ViewGroup) {
    ViewCompat.setOnApplyWindowInsetsListener(bottomContainerView) { v, windowInsets ->
        val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
        v.setPadding(insets.left, insets.top, insets.right, insets.bottom)

        WindowInsetsCompat.CONSUMED
    }
}

fun applyTutorialInsets(view: MainPageTutorialView, promotionsTutorial: PromotionsPageTutorialView) {
    ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
        val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())

        view.insetsTop = insets.top.toFloat()
        view.insetsLeft = insets.left.toFloat()
        view.insetsRight = insets.right.toFloat()
        view.insetsBottom = insets.bottom.toFloat()
        promotionsTutorial.insetsTop = insets.top.toFloat()
        promotionsTutorial.insetsBottom = insets.bottom.toFloat()

        WindowInsetsCompat.CONSUMED
    }
}

}

Everything is working fine, until I call AppCompatDelegate.setDefaultNightMode(//no matter which mode) to change the theme for example from Day to Night. Then as expected Activity is being recreated and restored all its state including fragments, but the edge-to-edge does not apply again and the setOnApplyInsetsListeners haven't called

What I've already checked:

  1. enableEdgeToEdge() is being called before setContentView()
  2. setOnApplyWindowInsetsListener called inside onCreate() after setContentView()

What I've already tried:

  1. Called enableEdgeToEdge() in onStart, onResume (didn't work)
  2. Enabled configChanges="uiMode" and called enableEdgeToEdge() inside onConfigurationChanged() and manually called recreate() (didn't work)
  3. I had a launchMode="singleTop" in my AndroidManifest.xml, tried to remove it (didn't work)

This bug reproduced by me on an emulator, and some Samsung devices. On my personal Pixel 9 everything works fine as expected.

Here is some examples.

Dark mode enabled (AppCompatDelegate.MODE_NIGHT_YES)

enter image description here

Light mode enabled (AppCompatDelegate.MODE_NIGHT_NO)

(Don't pay attention to isAppearanceLightStatusBar thing, I will fix that later)

enter image description here

like image 657
Nazar Taraniuk Avatar asked Sep 01 '25 03:09

Nazar Taraniuk


2 Answers

As Mike M. mentioned, there was a bug during activity recreation and his suggested workaround is the solution. So, for those who also faced this issue, you should do:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Add these 3 lines to your code
    if (savedInstanceState != null && Build.VERSION.SDK_INT >= 35) {
        WindowCompat.setDecorFitsSystemWindows(window, false)
    }
    enableEdgeToEdge()
}
like image 132
Nazar Taraniuk Avatar answered Sep 02 '25 15:09

Nazar Taraniuk


In my case, even the accepted answer didn't work. I am not sure if that would happen on real devices too, cause I have checked only on emulators, but my fix was to use UiModeManager for API 31+.

val uiModeManager = getSystemService(UI_MODE_SERVICE) as UiModeManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    uiModeManager.setApplicationNightMode(UiModeManager.MODE_NIGHT_YES)
} else {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}

P.S. No need to call:

WindowCompat.setDecorFitsSystemWindows(window, false)
like image 42
Hayk Mkrtchyan Avatar answered Sep 02 '25 15:09

Hayk Mkrtchyan