fix: library regressions - #190
Conversation
There was a problem hiding this comment.
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.
| if (windowParams.gravity == (Gravity.START or Gravity.TOP)) { | ||
| windowParams.x = windowParams.x.coerceIn(0, maxXCoordinate) | ||
| windowParams.y = windowParams.y.coerceIn(0, maxYCoordinate) | ||
| } |
There was a problem hiding this comment.
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)
}| if (decorView.parent != null) { | ||
| windowManager.removeViewImmediate(decorView) | ||
| } |
There was a problem hiding this comment.
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)
}| if (decorView.parent != null) { | ||
| windowManager.removeViewImmediate(decorView) | ||
| } else if (wasShowing) { |
There was a problem hiding this comment.
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) {|
/gemini summary |
Summary of ChangesThis 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
Activity
|
…nt lag when screen is off
…tion scale handling
Pull Request Type
Related issue
Description
Screenshots
Testing
Additional context