Skip to content

fix: library regressions - #190

Draft
ArthurKun21 wants to merge 11 commits into
masterfrom
fix/freezing-with-the-alert-dialog
Draft

fix: library regressions#190
ArthurKun21 wants to merge 11 commits into
masterfrom
fix/freezing-with-the-alert-dialog

Conversation

@ArthurKun21

@ArthurKun21 ArthurKun21 commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Pull Request Type

  • Chore
  • Bugfix
  • Feature Implementation
  • Documentation
  • Other

Related issue

Description

  • Replaced createLifecycleAwareWindowRecomposer with a window-owned recomposer in CoreFloatingWindow.kt. AndroidX permanently cancels lifecycle-aware recomposers when hide() detaches the view, causing frozen content and dialogs after showing again.
  • Both ComposeFloatingWindow and ComposeServiceFloatingWindow now use the corrected recomposer lifecycle.
  • Reset stale frame-update scheduling after detach, preventing coordinate updates from becoming permanently blocked.
  • Avoided incorrectly clamping coordinates when callers use custom gravity instead of START | TOP.
  • Fixed rapid hide() → show() calls so the pending fade-out cannot detach a newly reshown window.
  • Made close() reliably remove a window even while its hide animation is still running.
  • Added regression coverage for recomposition after hide/show and rapid hide/show.

Screenshots

Testing

Additional context

@ArthurKun21 ArthurKun21 added the bug Something isn't working label Jul 14, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves the lifecycle and state management of floating windows, specifically keeping the Compose recomposer alive when the window is hidden and detached, and handling quick show/hide transitions. The review feedback highlights three main areas for improvement: making the gravity check more robust by using Gravity.getAbsoluteGravity to support different layout directions and flags, and defensively handling cases where the decorView parent is a ViewGroup during removal and destruction to prevent potential IllegalArgumentException crashes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +273 to +276
if (windowParams.gravity == (Gravity.START or Gravity.TOP)) {
windowParams.x = windowParams.x.coerceIn(0, maxXCoordinate)
windowParams.y = windowParams.y.coerceIn(0, maxYCoordinate)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current check windowParams.gravity == (Gravity.START or Gravity.TOP) is very strict and might fail if additional gravity flags (such as Gravity.CLIP_VERTICAL, Gravity.FILL_HORIZONTAL, etc.) are set, or if Gravity.LEFT is used instead of Gravity.START.

To make this check more robust and support all variations of top-start/top-left gravity, we can resolve the absolute gravity using Gravity.getAbsoluteGravity and check the horizontal and vertical gravity masks.

        val absoluteGravity = Gravity.getAbsoluteGravity(windowParams.gravity, decorView.layoutDirection)
        if ((absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT &&
            (absoluteGravity and Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP
        ) {
            windowParams.x = windowParams.x.coerceIn(0, maxXCoordinate)
            windowParams.y = windowParams.y.coerceIn(0, maxYCoordinate)
        }

Comment on lines +353 to +355
if (decorView.parent != null) {
windowManager.removeViewImmediate(decorView)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If decorView.parent is a ViewGroup (and not the WindowManager's ViewRootImpl), calling windowManager.removeViewImmediate(decorView) will throw an IllegalArgumentException because the view is not attached to the WindowManager.

To prevent potential crashes, we should check if the parent is a ViewGroup and remove it from there, or only call removeViewImmediate if it is attached to the WindowManager.

                            val parent = decorView.parent
                            if (parent is ViewGroup) {
                                parent.removeView(decorView)
                            } else if (parent != null) {
                                windowManager.removeViewImmediate(decorView)
                            }

Comment on lines +463 to +465
if (decorView.parent != null) {
windowManager.removeViewImmediate(decorView)
} else if (wasShowing) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the issue in hide(), if decorView.parent is a ViewGroup during destruction, calling windowManager.removeViewImmediate(decorView) will throw an IllegalArgumentException. We should handle ViewGroup parents defensively here as well.

            val parent = decorView.parent
            if (parent is ViewGroup) {
                parent.removeView(decorView)
            } else if (parent != null) {
                windowManager.removeViewImmediate(decorView)
            } else if (wasShowing) {

@ArthurKun21

Copy link
Copy Markdown
Owner Author

/gemini summary

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

This pull request addresses several regressions introduced in the 1.7.0 update related to floating window lifecycle and state management. The primary focus is on decoupling the Compose recomposer from the view's attachment lifecycle, which was causing content to freeze after a window was hidden and shown again. Additionally, the changes improve the reliability of window removal during destruction and refine coordinate handling to support custom gravity configurations.

Highlights

  • Recomposer Lifecycle: Replaced the lifecycle-aware window recomposer with a custom window-owned recomposer to prevent content freezing caused by permanent cancellation during view detachment.
  • Window Management Robustness: Improved window hide/show logic to handle rapid state transitions, ensuring that pending fade-out animations do not interfere with newly shown windows.
  • Coordinate Clamping: Restricted coordinate clamping to START | TOP gravity to prevent incorrect behavior when using custom gravity settings.
  • Regression Testing: Added new instrumentation tests to verify recomposition after hide/show cycles and ensure window attachment stability during rapid toggling.
Activity
  • Pull request created by ArthurKun21.
  • Automated review comments provided suggestions for more robust gravity checks and defensive view removal logic.
  • Author requested a summary via the /gemini command.

@ArthurKun21 ArthurKun21 changed the title fix: regressions from 1.7.0 update fix: library regressions Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant