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_resource.dart';
|
||||
export 'src/services/keyboard.dart';
|
||||
export 'src/services/print.dart';
|
||||
export 'src/services/service_registry.dart';
|
||||
export 'src/services/shell.dart';
|
||||
|
@ -16,6 +16,8 @@ import 'events.dart';
|
||||
import 'hit_test.dart';
|
||||
import 'pointer_router.dart';
|
||||
|
||||
typedef void GesturerExceptionHandler(PointerEvent event, HitTestTarget target, dynamic exception, StackTrace stack);
|
||||
|
||||
abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestable {
|
||||
|
||||
void initInstances() {
|
||||
@ -76,11 +78,34 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl
|
||||
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
|
||||
void dispatchEvent(PointerEvent event, HitTestResult result) {
|
||||
assert(result != null);
|
||||
for (HitTestEntry entry in result.path)
|
||||
entry.target.handleEvent(event, entry);
|
||||
for (HitTestEntry entry in result.path) {
|
||||
try {
|
||||
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) {
|
||||
|
@ -2,11 +2,15 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'events.dart';
|
||||
|
||||
/// A callback that receives a [PointerEvent]
|
||||
typedef void PointerRoute(PointerEvent event);
|
||||
|
||||
typedef void PointerExceptionHandler(PointerRouter source, PointerEvent event, PointerRoute route, dynamic exception, StackTrace stack);
|
||||
|
||||
/// A routing table for [PointerEvent] events.
|
||||
class PointerRouter {
|
||||
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
|
||||
@ -34,14 +38,38 @@ class PointerRouter {
|
||||
_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) {
|
||||
List<PointerRoute> routes = _routeMap[event.pointer];
|
||||
if (routes == null)
|
||||
return;
|
||||
for (PointerRoute route in new List<PointerRoute>.from(routes))
|
||||
route(event);
|
||||
for (PointerRoute route in new List<PointerRoute>.from(routes)) {
|
||||
try {
|
||||
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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:convert' show JSON;
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:ui' as ui;
|
||||
@ -11,7 +10,8 @@ import 'dart:ui' as ui;
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/rendering.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.
|
||||
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