Commit 4e23ecd6 authored by Hixie's avatar Hixie

Catch exceptions in pointer handling

If we don't catch these exceptions, we get confused about what's going
on with the pointers, and the app basically stops working.
parent ff2c8b48
......@@ -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();
}
}
// 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();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment