Merge pull request #946 from Hixie/pointerExceptions
Catch exceptions in pointer handling
This commit is contained in:
commit
7dad780f13
@ -19,5 +19,6 @@ export 'src/services/image_cache.dart';
|
|||||||
export 'src/services/image_decoder.dart';
|
export 'src/services/image_decoder.dart';
|
||||||
export 'src/services/image_resource.dart';
|
export 'src/services/image_resource.dart';
|
||||||
export 'src/services/keyboard.dart';
|
export 'src/services/keyboard.dart';
|
||||||
|
export 'src/services/print.dart';
|
||||||
export 'src/services/service_registry.dart';
|
export 'src/services/service_registry.dart';
|
||||||
export 'src/services/shell.dart';
|
export 'src/services/shell.dart';
|
||||||
|
@ -16,6 +16,8 @@ import 'events.dart';
|
|||||||
import 'hit_test.dart';
|
import 'hit_test.dart';
|
||||||
import 'pointer_router.dart';
|
import 'pointer_router.dart';
|
||||||
|
|
||||||
|
typedef void GesturerExceptionHandler(PointerEvent event, HitTestTarget target, dynamic exception, StackTrace stack);
|
||||||
|
|
||||||
abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestable {
|
abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestable {
|
||||||
|
|
||||||
void initInstances() {
|
void initInstances() {
|
||||||
@ -76,11 +78,34 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl
|
|||||||
result.add(new HitTestEntry(this));
|
result.add(new HitTestEntry(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This callback is invoked whenever an exception is caught by the Gesturer
|
||||||
|
/// binding. The 'event' argument is the pointer event that was being routed.
|
||||||
|
/// The 'target' argument is the class whose handleEvent function threw the
|
||||||
|
/// exception. The 'exception' argument contains the object that was thrown,
|
||||||
|
/// and the 'stack' argument contains the stack trace. The callback is invoked
|
||||||
|
/// after the information is printed to the console.
|
||||||
|
GesturerExceptionHandler debugGesturerExceptionHandler;
|
||||||
|
|
||||||
/// Dispatch the given event to the path of the given hit test result
|
/// Dispatch the given event to the path of the given hit test result
|
||||||
void dispatchEvent(PointerEvent event, HitTestResult result) {
|
void dispatchEvent(PointerEvent event, HitTestResult result) {
|
||||||
assert(result != null);
|
assert(result != null);
|
||||||
for (HitTestEntry entry in result.path)
|
for (HitTestEntry entry in result.path) {
|
||||||
|
try {
|
||||||
entry.target.handleEvent(event, entry);
|
entry.target.handleEvent(event, entry);
|
||||||
|
} catch (exception, stack) {
|
||||||
|
debugPrint('-- EXCEPTION --');
|
||||||
|
debugPrint('The following exception was raised while dispatching a pointer event:');
|
||||||
|
debugPrint('$exception');
|
||||||
|
debugPrint('Stack trace:');
|
||||||
|
debugPrint('$stack');
|
||||||
|
debugPrint('Event:');
|
||||||
|
debugPrint('$event');
|
||||||
|
debugPrint('Target:');
|
||||||
|
debugPrint('${entry.target}');
|
||||||
|
if (debugGesturerExceptionHandler != null)
|
||||||
|
debugGesturerExceptionHandler(event, entry.target, exception, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleEvent(PointerEvent event, HitTestEntry entry) {
|
void handleEvent(PointerEvent event, HitTestEntry entry) {
|
||||||
|
@ -2,11 +2,15 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'events.dart';
|
import 'events.dart';
|
||||||
|
|
||||||
/// A callback that receives a [PointerEvent]
|
/// A callback that receives a [PointerEvent]
|
||||||
typedef void PointerRoute(PointerEvent event);
|
typedef void PointerRoute(PointerEvent event);
|
||||||
|
|
||||||
|
typedef void PointerExceptionHandler(PointerRouter source, PointerEvent event, PointerRoute route, dynamic exception, StackTrace stack);
|
||||||
|
|
||||||
/// A routing table for [PointerEvent] events.
|
/// A routing table for [PointerEvent] events.
|
||||||
class PointerRouter {
|
class PointerRouter {
|
||||||
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
|
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
|
||||||
@ -34,14 +38,38 @@ class PointerRouter {
|
|||||||
_routeMap.remove(pointer);
|
_routeMap.remove(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls the routes registed for this pointer event.
|
/// This callback is invoked whenever an exception is caught by the pointer
|
||||||
|
/// router. The 'source' argument is the [PointerRouter] object that caught
|
||||||
|
/// the exception. The 'event' argument is the pointer event that was being
|
||||||
|
/// routed. The 'route' argument is the callback that threw the exception. The
|
||||||
|
/// 'exception' argument contains the object that was thrown, and the 'stack'
|
||||||
|
/// argument contains the stack trace. The callback is invoked after the
|
||||||
|
/// information (exception, stack trace, and event; not the route callback
|
||||||
|
/// itself) is printed to the console.
|
||||||
|
PointerExceptionHandler debugPointerExceptionHandler;
|
||||||
|
|
||||||
|
/// Calls the routes registered for this pointer event.
|
||||||
///
|
///
|
||||||
/// Calls the routes in the order in which they were added to the route.
|
/// Routes are called in the order in which they were added to the
|
||||||
|
/// PointerRouter object.
|
||||||
void route(PointerEvent event) {
|
void route(PointerEvent event) {
|
||||||
List<PointerRoute> routes = _routeMap[event.pointer];
|
List<PointerRoute> routes = _routeMap[event.pointer];
|
||||||
if (routes == null)
|
if (routes == null)
|
||||||
return;
|
return;
|
||||||
for (PointerRoute route in new List<PointerRoute>.from(routes))
|
for (PointerRoute route in new List<PointerRoute>.from(routes)) {
|
||||||
|
try {
|
||||||
route(event);
|
route(event);
|
||||||
|
} catch (exception, stack) {
|
||||||
|
debugPrint('-- EXCEPTION --');
|
||||||
|
debugPrint('The following exception was raised while routing a pointer event:');
|
||||||
|
debugPrint('$exception');
|
||||||
|
debugPrint('Stack trace:');
|
||||||
|
debugPrint('$stack');
|
||||||
|
debugPrint('Event:');
|
||||||
|
debugPrint('$event');
|
||||||
|
if (debugPointerExceptionHandler != null)
|
||||||
|
debugPointerExceptionHandler(this, event, route, exception, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
|
||||||
import 'dart:convert' show JSON;
|
import 'dart:convert' show JSON;
|
||||||
import 'dart:developer' as developer;
|
import 'dart:developer' as developer;
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
@ -11,7 +10,8 @@ import 'dart:ui' as ui;
|
|||||||
import 'package:flutter/painting.dart';
|
import 'package:flutter/painting.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
|
||||||
|
export 'package:flutter/services.dart' show debugPrint;
|
||||||
|
|
||||||
/// Causes each RenderBox to paint a box around its bounds.
|
/// Causes each RenderBox to paint a box around its bounds.
|
||||||
bool debugPaintSizeEnabled = false;
|
bool debugPaintSizeEnabled = false;
|
||||||
@ -127,43 +127,3 @@ Future<developer.ServiceExtensionResponse> _timeDilation(String method, Map<Stri
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a message to the console, which you can access using the "flutter"
|
|
||||||
/// tool's "logs" command ("flutter logs").
|
|
||||||
///
|
|
||||||
/// This function very crudely attempts to throttle the rate at which messages
|
|
||||||
/// are sent to avoid data loss on Android. This means that interleaving calls
|
|
||||||
/// to this function (directly or indirectly via [debugDumpRenderTree] or
|
|
||||||
/// [debugDumpApp]) and to the Dart [print] method can result in out-of-order
|
|
||||||
/// messages in the logs.
|
|
||||||
void debugPrint(String message) {
|
|
||||||
_debugPrintBuffer.addAll(message.split('\n'));
|
|
||||||
if (!_debugPrintScheduled)
|
|
||||||
_debugPrintTask();
|
|
||||||
}
|
|
||||||
int _debugPrintedCharacters = 0;
|
|
||||||
int _kDebugPrintCapacity = 16 * 1024;
|
|
||||||
Duration _kDebugPrintPauseTime = const Duration(seconds: 1);
|
|
||||||
Queue<String> _debugPrintBuffer = new Queue<String>();
|
|
||||||
Stopwatch _debugPrintStopwatch = new Stopwatch();
|
|
||||||
bool _debugPrintScheduled = false;
|
|
||||||
void _debugPrintTask() {
|
|
||||||
_debugPrintScheduled = false;
|
|
||||||
if (_debugPrintStopwatch.elapsed > _kDebugPrintPauseTime) {
|
|
||||||
_debugPrintStopwatch.stop();
|
|
||||||
_debugPrintStopwatch.reset();
|
|
||||||
_debugPrintedCharacters = 0;
|
|
||||||
}
|
|
||||||
while (_debugPrintedCharacters < _kDebugPrintCapacity && _debugPrintBuffer.length > 0) {
|
|
||||||
String line = _debugPrintBuffer.removeFirst();
|
|
||||||
_debugPrintedCharacters += line.length; // TODO(ianh): Use the UTF-8 byte length instead
|
|
||||||
print(line);
|
|
||||||
}
|
|
||||||
if (_debugPrintBuffer.length > 0) {
|
|
||||||
_debugPrintScheduled = true;
|
|
||||||
_debugPrintedCharacters = 0;
|
|
||||||
new Timer(_kDebugPrintPauseTime, _debugPrintTask);
|
|
||||||
} else {
|
|
||||||
_debugPrintStopwatch.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
46
packages/flutter/lib/src/services/print.dart
Normal file
46
packages/flutter/lib/src/services/print.dart
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
/// Prints a message to the console, which you can access using the "flutter"
|
||||||
|
/// tool's "logs" command ("flutter logs").
|
||||||
|
///
|
||||||
|
/// This function very crudely attempts to throttle the rate at which messages
|
||||||
|
/// are sent to avoid data loss on Android. This means that interleaving calls
|
||||||
|
/// to this function (directly or indirectly via [debugDumpRenderTree] or
|
||||||
|
/// [debugDumpApp]) and to the Dart [print] method can result in out-of-order
|
||||||
|
/// messages in the logs.
|
||||||
|
void debugPrint(String message) {
|
||||||
|
_debugPrintBuffer.addAll(message.split('\n'));
|
||||||
|
if (!_debugPrintScheduled)
|
||||||
|
_debugPrintTask();
|
||||||
|
}
|
||||||
|
int _debugPrintedCharacters = 0;
|
||||||
|
int _kDebugPrintCapacity = 16 * 1024;
|
||||||
|
Duration _kDebugPrintPauseTime = const Duration(seconds: 1);
|
||||||
|
Queue<String> _debugPrintBuffer = new Queue<String>();
|
||||||
|
Stopwatch _debugPrintStopwatch = new Stopwatch();
|
||||||
|
bool _debugPrintScheduled = false;
|
||||||
|
void _debugPrintTask() {
|
||||||
|
_debugPrintScheduled = false;
|
||||||
|
if (_debugPrintStopwatch.elapsed > _kDebugPrintPauseTime) {
|
||||||
|
_debugPrintStopwatch.stop();
|
||||||
|
_debugPrintStopwatch.reset();
|
||||||
|
_debugPrintedCharacters = 0;
|
||||||
|
}
|
||||||
|
while (_debugPrintedCharacters < _kDebugPrintCapacity && _debugPrintBuffer.length > 0) {
|
||||||
|
String line = _debugPrintBuffer.removeFirst();
|
||||||
|
_debugPrintedCharacters += line.length; // TODO(ianh): Use the UTF-8 byte length instead
|
||||||
|
print(line);
|
||||||
|
}
|
||||||
|
if (_debugPrintBuffer.length > 0) {
|
||||||
|
_debugPrintScheduled = true;
|
||||||
|
_debugPrintedCharacters = 0;
|
||||||
|
new Timer(_kDebugPrintPauseTime, _debugPrintTask);
|
||||||
|
} else {
|
||||||
|
_debugPrintStopwatch.start();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user