Hey y’all, I’m working on a thermostat view in jet...
# compose
a
Hey y’all, I’m working on a thermostat view in jetpack compose, and I was facing an issue using
pointerInteropFilter
on the knob views in conjunction with
pointerInput
on a
Canvas
view underneath. Multitouch breaks with a NPE. I have a small sample pasted below the stack trace, and some context explaining why I need to do things this way
In case y’all are wondering what it looks like, for some context
Here’s the stack trace
Copy code
2022-03-31 11:07:30.166 15447-15447/com.stratisiot.mobile E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.stratisiot.mobile, PID: 15447
    java.lang.NullPointerException
        at androidx.compose.foundation.gestures.DragGestureDetectorKt.awaitDragOrCancellation-rnUCldI(DragGestureDetector.kt:844)
        at androidx.compose.foundation.gestures.DragGestureDetectorKt$awaitDragOrCancellation$1.invokeSuspend(Unknown Source:15)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
        at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
        at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
        at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:509)
        at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:404)
        at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:417)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:310)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
        at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:179)
        at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:98)
        at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:80)
        at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1223)
        at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1173)
        at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1112)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3120)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2801)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3120)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2801)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3120)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2801)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3120)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2801)
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:498)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1890)
        at android.app.Activity.dispatchTouchEvent(Activity.java:4202)
        at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:456)
        at android.view.View.dispatchPointerEvent(View.java:14858)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6446)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:6247)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5725)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5782)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5748)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5913)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5756)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5970)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5729)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5782)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5748)
2022-03-31 11:07:30.167 15447-15447/com.stratisiot.mobile E/AndroidRuntime:     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5756)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5729)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8696)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8647)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8616)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8819)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:259)
        at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
        at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:239)
        at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:8776)
        at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:8905)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1037)
        at android.view.Choreographer.doCallbacks(Choreographer.java:845)
        at android.view.Choreographer.doFrame(Choreographer.java:772)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7870)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Copy code
@Composable
fun Reproduction(modifier: Modifier = Modifier) {
    BoxWithConstraints(modifier) {
        Canvas(Modifier.fillMaxSize().pointerInput(Unit) {
            detectDragGestures(
                onDrag = { _, dragAmount -> println(dragAmount) }
            )
        }) {
            drawCircle(Color.Red, size.width / 3)
        }

        Box(Modifier.size(48.dp).background(Color.Yellow).pointerInteropFilter { event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> { println("DOWN") }
            }

            false
        })
    }
}

@Composable
@Preview
private fun Reproduction_Preview() {
    Reproduction(Modifier.padding(48.dp).aspectRatio(1F))
}
I’m on 1.2.0-alpha06
For context, I need pointerInteropFilter to pass through the touch event, but detect when one of the knobs are touched so I can perform a bunch of circle math to get the progress of the currently downed knob
Also, this happens only with multutouch
j
Would you mind filing an issue with the repro here? 🙂
a
Sure thing @jossiwolf
You may have linked an internal facing thing, I’ve created an issue on the public tracker: https://issuetracker.google.com/issues/227759166
j
Indeed I have, ty Andrew!
a
No prob!
136 Views