Fixed
Status Update
Comments
ap...@google.com <ap...@google.com> #2
Project: platform/frameworks/support
Branch: androidx-main
Author: Louis Pullen-Freilich <
Link:
Fixes NPE when recording drawContent to a GraphicsLayer
Expand for full commit details
Fixes NPE when recording drawContent to a GraphicsLayer
In some cases (for example when software rendering the graphics layer is required on API levels where the graphics layer implementation doesn't support software rendering) drawing a graphics layer requires drawing the drawBlock passed to record, outside of the draw pass. Since we use a shared draw scope for all draw modifier nodes, this means that we capture a reference to the scope but we don't have the node information anymore to be able to draw it. This CL fixes this issue by making sure that our ContentDrawScope implementation properly restores the node state when drawing a previously recorded drawBlock.
To avoid this issue it is important to use the record function inside DrawScope for this specific use case, and avoid capturing the draw scope in a lambda otherwise.
This CL also updates the CacheDrawScope to use the record function provided by the DrawScope to avoid this issue from occuring inside cache drawing nodes.
Test: DrawModifierTest
Fixes: b/389046242
Relnote: "Fixed an occasional NPE when using `GraphicsLayer.record { this@ContentDrawScope.drawContent() }`. If you are recording drawContent() in this way, make sure to use the GraphicsLayer#record extension function inside DrawScope, and not the member function on GraphicsLayer."
Change-Id: I75fc026069666b61cdd7e5c377fa4da706f985d8
Files:
- M
compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
- M
compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
- M
compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeDrawScope.kt
Hash: 8025e8c6128dd3cf148684111953fbac71b55ac2
Date: Fri Jan 10 16:53:20 2025
ap...@google.com <ap...@google.com> #3
Project: platform/frameworks/support
Branch: androidx-main
Author: Louis Pullen-Freilich <
Link:
Revert^2 "Fixes issue with dragAndDropSource preventing child invalidations"
Expand for full commit details
Revert^2 "Fixes issue with dragAndDropSource preventing child invalidations"
This reverts commit 3d5fd7d04bdd7f02ee2b215af68b2832e06134bf.
Reason for revert: Underlying bug b/389046242 is now resolved
Fixes: b/379682458
Test: DragAndDropSourceTest
Test: AndroidDragAndDropIntegrationTest
Change-Id: I07cb2a4091b46d862628bf17625ae9d9eb087641
Files:
- A
compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/draganddrop/DragAndDropSourceTest.kt
- M
compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/draganddrop/AndroidDragAndDropSource.android.kt
Hash: 3c48a0fbd3c2902a6a7acb6c8b474a4928b1be41
Date: Mon Jan 13 09:46:38 2025
na...@google.com <na...@google.com> #4
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.compose.foundation:foundation:1.8.0-beta01
androidx.compose.foundation:foundation-android:1.8.0-beta01
androidx.compose.foundation:foundation-jvmstubs:1.8.0-beta01
androidx.compose.foundation:foundation-linuxx64stubs:1.8.0-beta01
androidx.compose.ui:ui-android:1.8.0-beta01
androidx.compose.ui:ui-jvmstubs:1.8.0-beta01
androidx.compose.ui:ui-linuxx64stubs:1.8.0-beta01
Description
Some more details in b/388353336
Start of trace:
This happens because when we draw we use a shared ContentDrawScope implementation that we render all DrawModifierNodes in. We do this by mutating a property as we draw successive nodes. However, this means that if anyone captures a reference to this draw scope and tries to draw it later on, this will cause a NPE error as we don't know what the 'current node' that needs to be drawn in.
For the general case this is an error and scopes shouldn't be captured and stored outside the scope in this way, but for GraphicsLayer this is needed when recording drawContent to support some edge cases, such as when we need to draw a layer implementation that can't be drawn in software, within software rendering (such as drawing to a Bitmap). For this we just end up re-invoking the draw block we captured.
We considered some solutions where we would allocate a new draw scope instance per modifier, but this adds some overhead and 'storing' these draw scopes for future use is challenging. (we considered putting them on the node object, in a map on the node coordinator, or some other chain structure on the node coordinator, but none of these are really great)
Instead we can explicitly support the GraphicsLayer.record case by overriding the DrawScope#GraphicsLayer.record function and making it handle this case properly. This can still cause issues if using the non-DrawScope scoped record function, but developers should move to the DrawScope one instead.