From ba38c446eaf45294319bd414d4199d68774029cb Mon Sep 17 00:00:00 2001 From: snowykte0426 Date: Sat, 15 Aug 2026 19:44:07 +0900 Subject: [PATCH] fix(edge-to-edge): keep the status bar visible in message selection mode With `windowActionModeOverlay` enabled, AppCompat offsets the contextual action bar below the status bar and adds an opaque guard view behind it to cover the gap. It picks the guard's colour from the deprecated SYSTEM_UI_FLAG_LIGHT_STATUS_BAR flag, and on API 35 and above nothing sets that flag any more: WindowInsetsControllerCompat applies the appearance only through setSystemBarsAppearance() rather than mirroring it onto the old flag. The guard was therefore always black, and because the window is drawn edge-to-edge that black rectangle covered the clock and the status icons as soon as a message was selected. The AppBarLayout already paints the status bar area, so the guard only needs to get out of the way. Clear its background from the insets listener that BaseActivity installs: AppCompat updates the guard from its own listener on the sub decor, which runs before the insets reach that layout, so the guard is cleared again every time AppCompat recolours it. Fixes #11305 --- .../java/com/fsck/k9/ui/base/BaseActivity.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/BaseActivity.kt b/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/BaseActivity.kt index eb01390af13..932fd72c3fc 100644 --- a/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/BaseActivity.kt +++ b/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/BaseActivity.kt @@ -1,8 +1,10 @@ package com.fsck.k9.ui.base import android.content.Context +import android.graphics.Color import android.os.Build import android.os.Bundle +import android.view.View import android.view.ViewGroup import androidx.activity.enableEdgeToEdge import androidx.annotation.LayoutRes @@ -15,6 +17,7 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat.Type.displayCutout import androidx.core.view.WindowInsetsCompat.Type.ime import androidx.core.view.WindowInsetsCompat.Type.systemBars +import androidx.core.view.children import androidx.core.view.updatePadding import androidx.lifecycle.asLiveData import com.fsck.k9.controller.push.PushController @@ -134,10 +137,38 @@ abstract class BaseActivity( bottom = max(insets.bottom, imeInsets.bottom), ) + hideActionModeStatusGuard() + WindowInsetsCompat.CONSUMED } } + /** + * Hides the status bar guard AppCompat draws while a contextual action mode is visible. + * + * With `windowActionModeOverlay` enabled, AppCompat offsets the contextual action bar below the status bar and + * fills the space that is left over with an opaque view. It picks the colour of that view from the deprecated + * `SYSTEM_UI_FLAG_LIGHT_STATUS_BAR` flag. On API 35 and above nothing sets that flag any more, because + * `WindowInsetsControllerCompat` then applies the appearance only through `setSystemBarsAppearance()` instead of + * mirroring it onto the old flag, so the guard always ends up black and hides the clock and the status icons. + * This window is drawn edge-to-edge and the AppBarLayout behind the guard already covers that area, so the guard + * just needs to get out of the way. + * + * AppCompat updates the guard from its own insets listener on the sub decor, which runs before the insets reach the + * layout installed by [setLayout]. Doing this from there means the guard is cleared again every time AppCompat + * recolours it. + */ + private fun hideActionModeStatusGuard() { + val subDecor = findViewById(android.R.id.content)?.parent as? ViewGroup ?: return + + // AppCompat adds the guard as an id-less, plain View child of the sub decor. The children it puts there + // otherwise are the content frame and the contextual action bar, which are both ViewGroups with an id. + // If that ever stops being unambiguous, leave every one of them alone rather than recolour a guess. + subDecor.children + .singleOrNull { it.javaClass == View::class.java && it.id == View.NO_ID } + ?.setBackgroundColor(Color.TRANSPARENT) + } + protected fun recreateCompat() { ActivityCompat.recreate(this) }