Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'_initialButtons == kPrimaryButton': is not true. #75061

Closed
rahul-2501 opened this issue Jan 30, 2021 · 7 comments · Fixed by #75943
Closed

'_initialButtons == kPrimaryButton': is not true. #75061

rahul-2501 opened this issue Jan 30, 2021 · 7 comments · Fixed by #75943
Assignees
Labels
c: crash Stack traces logged to the console customer: money (g3) f: gestures flutter/packages/flutter/gestures repository. f: scrolling Viewports, list views, slivers, etc. found in release: 1.22 Found to occur in 1.22 found in release: 1.26 Found to occur in 1.26 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P0 Critical issues such as a build break or regression r: fixed Issue is closed as already fixed in a newer version

Comments

@rahul-2501
Copy link

rahul-2501 commented Jan 30, 2021

Corresponds to Google internal bug b/179634050

  1. Run flutter create bug.
  2. Update the files as follows:
import 'package:flutter/material.dart';

class StartPage extends StatefulWidget {
  @override
  _StartPageState createState() => _StartPageState();
}

class _StartPageState extends State<StartPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Start',
          style: TextStyle(fontSize: 30, fontWeight: FontWeight.w700),
        ),
        centerTitle: false,
        backgroundColor: Color(0xff06060c),
      ),
      backgroundColor: Color(0xff06060c),
      body: Column(
        children: [
          Expanded(
            child: ListView(
              children: [
                Container(
                  decoration:
                      BoxDecoration(borderRadius: BorderRadius.circular(10)),
                  height: 170,
                  child: ListView.builder(
                    scrollDirection: Axis.horizontal,
                    itemCount: 10,

                    itemBuilder: (BuildContext context, int index) {
                      return Row(
                        children: [
                          SizedBox(
                            width: 10,
                          ),
                          Container(
                            decoration: BoxDecoration(
                                color: Color(0xff16161e),
                                borderRadius: BorderRadius.circular(10)),
                            width: 150,
                            child: Center(
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Center(
                                    child: Text('Hello',
                                    style: TextStyle(fontSize: 30, fontWeight: FontWeight.w700,color: Colors.white),),
                                  )
                                ],
                              ),
                            ),
                          ),
                        ],
                      );
                    },
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
  1. To reproduce the bug tap on the nested Listview and any blank space at the same time.

Expected results: Outer Listview to work normal.

Actual results: Outer Listview crashes.

Logs

] flutter: ══╡ EXCEPTION CAUGHT BY GESTURE LIBRARY ╞═══════════════════════════════════════════════════════════
[ +7 ms] flutter: The following assertion was thrown while routing a pointer event:
[ ] flutter: 'package:flutter/src/gestures/monodrag.dart': Failed assertion: line 435 pos 12: '_initialButtons ==
[ ] flutter: kPrimaryButton': is not true.
[ ] flutter:
[ ] flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
[ ] flutter: more information in this error message to help you determine and fix the underlying cause.
[ ] flutter: In either case, please report this assertion by filing a bug on GitHub:
[ ] flutter: https://github.com/flutter/flutter/issues/new?template=BUG.md
[ ] flutter:
[ ] flutter: When the exception was thrown, this was the stack:
[ ] flutter: #2 DragGestureRecognizer._checkEnd (package:flutter/src/gestures/monodrag.dart:435:12)
[ ] flutter: #3 DragGestureRecognizer.didStopTrackingLastPointer (package:flutter/src/gestures/monodrag.dart:376:9)
[ +12 ms] flutter: #4 OneSequenceGestureRecognizer.stopTrackingPointer (package:flutter/src/gestures/recognizer.dart:342:9)
[ ] flutter: #5 DragGestureRecognizer._giveUpPointer (package:flutter/src/gestures/monodrag.dart:385:5)
[ ] flutter: #6 DragGestureRecognizer.handleEvent (package:flutter/src/gestures/monodrag.dart:282:9)
[ ] flutter: #7 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:77:12)
[ ] flutter: #8 PointerRouter._dispatchEventToRoutes. (package:flutter/src/gestures/pointer_router.dart:122:9)
[ ] flutter: #9 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
[ ] flutter: #10 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:120:18)
[ ] flutter: #11 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:106:7)
[ ] flutter: #12 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:358:19)
[ ] flutter: #13 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
[ ] flutter: #14 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
[ ] flutter: #15 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:295:7)
[ ] flutter: #16 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:240:7)
[ ] flutter: #17 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:213:7)
[ +1 ms] flutter: #21 _invoke1 (dart:ui/hooks.dart:265:10)
[ ] flutter: #22 _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)
[ +1 ms] flutter: (elided 5 frames from class _AssertionError and dart:async)
[ ] flutter:
[ ] flutter: router: Instance of 'PointerRouter'
[ ] flutter: route: Closure: (PointerEvent) => void from Function 'handleEvent':.
[ ] flutter: event: PointerMoveEvent#ed135(position: Offset(62.0, 506.5))
[ ] flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
[+6807 ms] flutter: Another exception was thrown: 'package:flutter/src/gestures/monodrag.dart': Failed assertion: line 435 pos 12:
'_initialButtons == kPrimaryButton': is not true.
[+26092 ms] flutter: Another exception was thrown: 'package:flutter/src/gestures/monodrag.dart': Failed assertion: line 435 pos 12:
'_initialButtons == kPrimaryButton': is not true.
[ +419 ms] flutter: Another exception was thrown: 'package:flutter/src/gestures/monodrag.dart': Failed assertion: line 435 pos 12:
'_initialButtons == kPrimaryButton': is not true.

[✓] Flutter (Channel stable, 1.22.6, on macOS 11.1 20C69 darwin-x64, locale en-IN)
• Flutter version 1.22.6 at /Users/rahul/Desktop/flutter
• Framework revision 9b2d32b (8 days ago), 2021-01-22 14:36:39 -0800
• Engine revision 2f0af37152
• Dart version 2.10.5

[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for
detailed instructions).
If the Android SDK has been installed to a custom location, set ANDROID_SDK_ROOT
to that location.
You may also want to add it to your PATH environment variable.

[✓] Xcode - develop for iOS and macOS (Xcode 12.4)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 12.4, Build version 12D4e
• CocoaPods version 1.10.0

[!] Android Studio (not installed)
• Android Studio not found; download from
https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for
detailed instructions).

[✓] VS Code (version 1.52.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.18.1

[✓] Connected device (1 available)
• R’s I (mobile) • c6467d3f454b96020193bf65ecad69cb68dbf640 • ios • iOS 14.3

@darshankawar
Copy link
Member

I was able to replicate this on latest stable as well as on master, but it doesn't throw the above error right away. Upon tapping on ListView and on blank space at the same time(doesn't replicate at first, have to repeat it few times), it first throws below exception:

======== Exception caught by gesture library =======================================================
The following _CastError was thrown while dispatching a pointer event:
Null check operator used on a null value

When the exception was thrown, this was the stack: 
#0      DragGestureRecognizer.acceptGesture (package:flutter/src/gestures/monodrag.dart:321:60)
#1      GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:157:27)
#2      GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:362:20)
#3      GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
#4      RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
...
Event: PointerUpEvent#6b4ba(position: Offset(136.7, 170.0))
  position: Offset(136.7, 170.0)
Target: <WidgetsFlutterBinding>
====================================================================================================


At this point, the app isn't responsive and gets stuck. Tapping anywhere on the screen then leads to below exception:

======== Exception caught by gesture library =======================================================
'package:flutter/src/gestures/monodrag.dart': Failed assertion: line 435 pos 12: '_initialButtons == kPrimaryButton': is not true.
====================================================================================================

======== Exception caught by gesture library =======================================================
'package:flutter/src/gestures/monodrag.dart': Failed assertion: line 435 pos 12: '_initialButtons == kPrimaryButton': is not true.
====================================================================================================

A similar issue related to Null check operator used on a null value was fixed and merged, #66250

Gesture exception '_initialButtons == kPrimaryButton': is not true. related issues were reported by many, the most latest / recent being this #71331, but was closed claiming to be a 3rd party issue.

@darshankawar darshankawar added f: scrolling Viewports, list views, slivers, etc. found in release: 1.22 Found to occur in 1.22 found in release: 1.26 Found to occur in 1.26 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on f: gestures flutter/packages/flutter/gestures repository. labels Feb 1, 2021
@jason-simmons
Copy link
Member

In this example there is a VerticalDragGestureRecognizer and a HorizontalDragGestureRecognizer.

When I reproduce the exception, the VerticalDragGestureRecognizer is receiving calls to:

  • addAllowedPointer for pointer 1
  • addAllowedPointer for pointer 2
  • acceptGesture for 2
  • didStopTrackingLastPointer for 1
  • acceptGesture for 1

The acceptGesture(2) clears the _lastPendingEventTimestamp. didStopTrackingLastPointer brings the DragGestureRecognizer back to the ready state. But _lastPendingEventTimestamp is still null at the time of the acceptGesture(1) call, resulting in the null exception.

@dkwingsmt Is it ever expected for an acceptGesture to occur after a didStopTrackingLastPointer for a pointer?

@dkwingsmt
Copy link
Contributor

Thank you all for the reports. This is definitely an issue I'd like to solve and one that has been haunting for a long time. The investigation and reproducing process you provided are extremely important and I greatly appreciate them. Although I'm currently stuck on a project that I really need to finish first, I'll come back afterwards ASAP. Meanwhile it'd be helpful if you have more investigation and/or PRs. Feel free to ping me for them.

@jason-simmons IIRC TapGestureRecognizer doesn't accept nor reject the pointer at PointerUpEvent, but relies on all other gesture recognizers to reject theirs for this tap to be recognized, which can happen way after the up event (which means "yes" to your question). Although I doubt if this situation should apply to the drag gestures.

@goderbauer
Copy link
Member

Here's a test case to repro the crash in isolation with some explanations of what's going on:

import 'package:flutter/gestures.dart';
import 'package:flutter_test/flutter_test.dart';

import 'gesture_tester.dart';

void main() {
  setUp(ensureGestureBinding);

  testGesture('should not crash - up', (GestureTester tester) {
    final VerticalDragGestureRecognizer v = VerticalDragGestureRecognizer()
      ..onStart = (_) { };
    final HorizontalDragGestureRecognizer h = HorizontalDragGestureRecognizer()
      ..onStart = (_) { };

    const PointerDownEvent down90 = PointerDownEvent(
      pointer: 90,
      position: Offset(10.0, 10.0),
    );

    const PointerUpEvent up90 = PointerUpEvent(
      pointer: 90,
      position: Offset(10.0, 10.0),
    );

    const PointerDownEvent down91 = PointerDownEvent(
      pointer: 91,
      position: Offset(20.0, 20.0),
    );

    const PointerUpEvent up91 = PointerUpEvent(
      pointer: 91,
      position: Offset(20.0, 20.0),
    );

    // "V" instantly wins the arena for pointer 90 because nobody else is
    // competing for it. This causes "V" to switch into the "accepted" state,
    // nulling out _lastPendingEventTimestamp.
    // "V" and "H" continue to compete for pointer 91 (pointer hasn't moved
    // enough to declare winner).
    v.addPointer(down90);
    GestureBinding.instance!.gestureArena.close(90);
    h.addPointer(down91);
    v.addPointer(down91);
    GestureBinding.instance!.gestureArena.close(91);
    tester.async.flushMicrotasks();

    GestureBinding.instance!.handleEvent(up90, HitTestEntry(MockHitTestTarget()));

    // "H" rejects the gesture of pointer 91, but "V" continues to
    // (incorrectly) compete for it in the arena (because this evaluates to
    // false: https://github.com/flutter/flutter/blob/980880e2b69764fb2d1ea18eafe6fffc466c6509/packages/flutter/lib/src/gestures/monodrag.dart#L314).
    // The arena is swept, and "V" becomes the winner. However, "V" has already
    // nulled out _lastPendingEventTimestamp (see above) and is therefore not in
    // a state to handle the "win" correctly.
    GestureBinding.instance!.handleEvent(up91, HitTestEntry(MockHitTestTarget()));
  });
}

class MockHitTestTarget implements HitTestTarget {
  @override
  void handleEvent(PointerEvent event, HitTestEntry entry) { }
}

The problem seems to be here:

_giveUpPointer(
event.pointer,
reject: event is PointerCancelEvent || _state ==_DragState.possible,
);

I believe, if the DragGestureRecognizer receives an up event for a pointer (here: 91) for which it was never told it had won the arena, it need to tell the gesture arena that it is no longer interested in winning for this pointer (i.e. we need to reject it). I'll see how I can express that in code to fix the bug.

@goderbauer goderbauer self-assigned this Feb 12, 2021
@goderbauer goderbauer added customer: money (g3) c: crash Stack traces logged to the console labels Feb 12, 2021
@darshankawar darshankawar added the r: fixed Issue is closed as already fixed in a newer version label Feb 17, 2021
@AlexV525
Copy link
Member

Should we cherry-pick this one into 1.22 or 1.26? Since it's a P2 issue.

@AlexV525
Copy link
Member

AlexV525 commented Feb 27, 2021

Request 1.22 cp due to stable channel at present. Also I'm concerning about the upgrading rate when a new stable version release, a nnbd one. FYI @xu-baolin

@github-actions
Copy link

github-actions bot commented Aug 4, 2021

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 4, 2021
@flutter-triage-bot flutter-triage-bot bot added the P0 Critical issues such as a build break or regression label Jun 28, 2023
@flutter-triage-bot flutter-triage-bot bot removed the P2 label Jun 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
c: crash Stack traces logged to the console customer: money (g3) f: gestures flutter/packages/flutter/gestures repository. f: scrolling Viewports, list views, slivers, etc. found in release: 1.22 Found to occur in 1.22 found in release: 1.26 Found to occur in 1.26 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P0 Critical issues such as a build break or regression r: fixed Issue is closed as already fixed in a newer version
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants