material-components / material-components-android

Modular and customizable Material Design UI components for Android
Apache License 2.0
16.37k stars 3.07k forks source link

NPE In BottomSheetBehaviour.onInterceptTouchEvent #43

Closed ouchadam closed 5 years ago

ouchadam commented 7 years ago

Overview

NullPointerException when attempting to delegate onInterceptTouchEvents to a BottomSheet before onLayoutChild has been called.

https://github.com/material-components/material-components-android/blob/master/lib/src/android/support/design/widget/BottomSheetBehavior.java#L281

The view reference is not checked before being interacted with, which the MotionEvent.ACTION_DOWN case is doing.

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.ref.Reference.get()' on a null object reference
     at android.support.design.widget.BottomSheetBehavior.onInterceptTouchEvent(BottomSheetBehavior.java:299)
     at android.support.design.widget.CoordinatorLayout.performIntercept(CoordinatorLayout.java:460)
     at android.support.design.widget.CoordinatorLayout.onInterceptTouchEvent(CoordinatorLayout.java:499)
     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2402)
     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
     at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:505)
     at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1863)
     at android.app.Activity.dispatchTouchEvent(Activity.java:3226)
     at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
     at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:467)
     at android.view.View.dispatchPointerEvent(View.java:10954)
     at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5051)
     at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4908)
     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4439)
     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4492)
     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4458)
     at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4591)
     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4466)
     at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4648)
     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4439)
     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4492)
     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4458)
     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4466)
     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4439)
     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6936)
     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6875)
     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6836)
     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7046)
     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
     at android.os.MessageQueue.nativePollOnce(Native Method)
     at android.os.MessageQueue.next(MessageQueue.java:323)
     at android.os.Looper.loop(Looper.java:136)
     at android.app.ActivityThread.main(ActivityThread.java:6692)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358) 

Reproduction steps

This can occur on older/slower devices by spamming touch events to the bottom sheet whilst the layout is being constructed.

Version number

Operating system and device

Am able to consistently reproduce on a Samsung S7 7.0. Was originally reported via crashyltics on Samsung Galaxy J1 4.4.4 and Oppo A37fw 5.1.1

tasomaniac commented 7 years ago

We are also able to reproduce this crash on Samsung Galaxy Tab. Just start an Activity that has BottomSheetBehavior possible by clicking a button. Just after clicking the button, continue to tap any place on the screen in a consistent speed. Doesn't even have to be too fast. Then it crashes.

We have support library 26.0.1

sczerwinski commented 6 years ago

We had the same issue on Samsung "Galaxy Tap Pro 8.4" (device name copy-pasted from Fabric – no typo here), Android 4.4.2, Support Library 26.1.0.

clj0020 commented 6 years ago

Having the same issue. NPE is caused by this line in BottomSheetBehavior on line 299 in onInterceptTouchEvent():

View scroll = mNestedScrollingChildRef.get();

mNestedScrollingChildRef is null in some cases. May just need to create your own BottomSheetBehavior with everything the same except for a nestedScrollingChildRef null check before this line. If it's null, just return false I guess. Gonna try that now.

srajkovic commented 5 years ago

This appears to have been fixed in support library 28.0.0, or material library 1.0.0 (same thing, just support vs androidx).

leticiarossi commented 5 years ago

This issue has been fixed in this commit https://github.com/material-components/material-components-android/commit/24c40ffa2aa0ba9ea33a3dd9755be050c49e4da0 and has been available since version 1.0.0

JayyyR commented 5 years ago

There's another issue related to this, we're seeing onStopNestedScroll get called before the view is laid out. However there's a block in this method where setStateInternal can get called. That's what's happening for us.

Then in setStateInternal, this line causes a crash:

View bottomSheet = viewRef.get();

Because viewRef hasn't been assigned

tatarize commented 5 years ago

That NPE appears to be different. That's for the nested scroller. There's a report of this still happening in 28.0.0 some middle versions seem like they were fixed. But the latest version actually doesn't seem to do the explicit check anymore.

See: https://stackoverflow.com/questions/56523241/nullpointerexception-on-viewdraghelper-gettouchslop

CristianMG commented 4 years ago

I have some reports about the same exception of you @JayyyR @tatarize, any idea that how it fix? Is a bit problem because happens about one user to each 5000.

yoavgray commented 4 years ago

We're seeing a huge influx of these NPEs. We're using version 28.0.0 as well and have many bottom sheets in the app so it's pretty hard to know where it's coming from:

java.lang.NullPointerException: Attempt to invoke virtual method 'int androidx.customview.widget.ViewDragHelper.getTouchSlop()' on a null object reference
    at com.google.android.material.bottomsheet.BottomSheetBehavior.onTouchEvent(BottomSheetBehavior.java:350)
    at androidx.coordinatorlayout.widget.CoordinatorLayout.performIntercept(CoordinatorLayout.java:476)
    at androidx.coordinatorlayout.widget.CoordinatorLayout.onTouchEvent(CoordinatorLayout.java:527)
    at android.view.View.dispatchTouchEvent(View.java:13473)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3216)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2888)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3222)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2904)
    at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:742)
    at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1880)
    at android.app.Activity.dispatchTouchEvent(Activity.java:3494)
    at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
    at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:700)
    at android.view.View.dispatchPointerEvent(View.java:13721)
    at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6175)
    at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5953)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5402)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5455)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5421)
    at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5580)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5429)
    at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5637)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5402)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5455)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5421)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5429)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5402)
    at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8467)
    at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8387)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8340)
    at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8582)
    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:198)
    at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
    at android.os.MessageQueue.next(MessageQueue.java:326)
    at android.os.Looper.loop(Looper.java:181)
    at android.app.ActivityThread.main(ActivityThread.java:7094)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

Is anyone else seeing this?