Merge pull request #812 from abarth/check_material

Widgets that depend on Material should assert that
diff --git a/examples/stocks/lib/main.dart b/examples/stocks/lib/main.dart
index f21d6fb..a2b6bda 100644
--- a/examples/stocks/lib/main.dart
+++ b/examples/stocks/lib/main.dart
@@ -77,7 +77,7 @@
     }
   }
 
-  Route _getRoute(NamedRouteSettings settings) {
+  Route _getRoute(RouteSettings settings) {
     List<String> path = settings.name.split('/');
     if (path[0] != '')
       return null;
diff --git a/packages/flutter/lib/src/material/material_app.dart b/packages/flutter/lib/src/material/material_app.dart
index 52f9836..0f2a907 100644
--- a/packages/flutter/lib/src/material/material_app.dart
+++ b/packages/flutter/lib/src/material/material_app.dart
@@ -106,7 +106,7 @@
 
   final HeroController _heroController = new HeroController();
 
-  Route _generateRoute(NamedRouteSettings settings) {
+  Route _generateRoute(RouteSettings settings) {
     RouteBuilder builder = config.routes[settings.name];
     if (builder != null) {
       return new MaterialPageRoute(
diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart
index 7ae2d1b..3c551a3 100644
--- a/packages/flutter/lib/src/material/page.dart
+++ b/packages/flutter/lib/src/material/page.dart
@@ -44,7 +44,7 @@
   MaterialPageRoute({
     this.builder,
     Completer<T> completer,
-    NamedRouteSettings settings: const NamedRouteSettings()
+    RouteSettings settings: const RouteSettings()
   }) : super(completer: completer, settings: settings) {
     assert(builder != null);
     assert(opaque);
diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart
index 34e6554..7667aee 100644
--- a/packages/flutter/lib/src/rendering/binding.dart
+++ b/packages/flutter/lib/src/rendering/binding.dart
@@ -56,10 +56,12 @@
       PointerDeviceKind kind = _pointerKindMap[datum.kind];
       switch (datum.type) {
         case PointerType.DOWN:
+          assert(!_pointers.containsKey(datum.pointer));
           _PointerState state = _pointers.putIfAbsent(
             datum.pointer,
             () => new _PointerState(position)
           );
+          assert(state.lastPosition == position);
           state.startNewPointer();
           state.setDown();
           yield new PointerAddedEvent(
@@ -96,13 +98,11 @@
           );
           break;
         case PointerType.MOVE:
-          _PointerState state = _pointers[datum.pointer];
           // If the service starts supporting hover pointers, then it must also
-          // start sending us ADDED and REMOVED data points. In the meantime, we
-          // only support "down" moves, and ignore spurious moves.
+          // start sending us ADDED and REMOVED data points.
           // See also: https://github.com/flutter/flutter/issues/720
-          if (state == null)
-            break;
+          assert(_pointers.containsKey(datum.pointer));
+          _PointerState state = _pointers[datum.pointer];
           assert(state.down);
           Offset offset = position - state.lastPosition;
           state.lastPosition = position;
@@ -129,8 +129,9 @@
           break;
         case PointerType.UP:
         case PointerType.CANCEL:
+          assert(_pointers.containsKey(datum.pointer));
           _PointerState state = _pointers[datum.pointer];
-          assert(state != null);
+          assert(state.down);
           assert(position == state.lastPosition);
           state.setUp();
           if (datum.type == PointerType.UP) {
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index 9a229c7..adc0e1e 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -1038,7 +1038,7 @@
   /// If this render object applies a transform before painting, apply that
   /// transform to the given matrix
   ///
-  /// Used by coordinate conversion functions to translate coordiantes local to
+  /// Used by coordinate conversion functions to translate coordinates local to
   /// one render object into coordinates local to another render object.
   void applyPaintTransform(Matrix4 transform) { }
 
diff --git a/packages/flutter/lib/src/widgets/event_recorder.dart b/packages/flutter/lib/src/widgets/event_recorder.dart
deleted file mode 100644
index f224043..0000000
--- a/packages/flutter/lib/src/widgets/event_recorder.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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 'package:flutter/gestures.dart';
-
-import 'basic.dart';
-import 'framework.dart';
-
-enum EventRecorderMode {
-  stop,
-  record
-}
-
-typedef void EventsReadyCallback(Iterable<PointerEvent> events);
-
-/// EventRecorder is a utility widget that allows input events occurring
-/// on the child to be recorded. The widget is initially in the "stop" state
-/// by default. When in the "record" state, all pointer input events
-/// occurring on the child are recorded into a buffer. When the "stop" state
-/// is entered again, the onEventsReady callback is invoked with a list of
-/// the recorded events.
-class EventRecorder extends StatefulComponent {
-  EventRecorder({
-    Key key,
-    this.child,
-    this.mode: EventRecorderMode.stop,
-    this.onEventsReady
-  });
-
-  final Widget child;
-  final EventRecorderMode mode;
-  final EventsReadyCallback onEventsReady;
-
-  _EventRecorderState createState() => new _EventRecorderState();
-}
-
-class _EventRecorderState extends State<EventRecorder> {
-
-  final List<PointerEvent> _events = <PointerEvent>[];
-
-  void didUpdateConfig(EventRecorder oldConfig) {
-    if (oldConfig.mode == EventRecorderMode.record &&
-        config.mode == EventRecorderMode.stop) {
-      config.onEventsReady(_events);
-      _events.clear();
-    }
-  }
-
-  void _recordEvent(PointerEvent event) {
-    if (config.mode == EventRecorderMode.record)
-      _events.add(event);
-  }
-
-  Widget build(BuildContext context) {
-    return new Listener(
-      onPointerDown: _recordEvent,
-      onPointerMove: _recordEvent,
-      onPointerUp: _recordEvent,
-      onPointerCancel: _recordEvent,
-      child: config.child
-    );
-  }
-
-}
diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart
index dcce4a8..b8fa67e 100644
--- a/packages/flutter/lib/src/widgets/navigator.dart
+++ b/packages/flutter/lib/src/widgets/navigator.dart
@@ -66,8 +66,8 @@
   }
 }
 
-class NamedRouteSettings {
-  const NamedRouteSettings({
+class RouteSettings {
+  const RouteSettings({
     this.name,
     this.mostValuableKeys,
     this.isInitialRoute: false
@@ -88,7 +88,7 @@
   }
 }
 
-typedef Route RouteFactory(NamedRouteSettings settings);
+typedef Route RouteFactory(RouteSettings settings);
 typedef void NavigatorTransactionCallback(NavigatorTransaction transaction);
 
 class NavigatorObserver {
@@ -123,9 +123,9 @@
     });
   }
 
-  static void push(BuildContext context, Route route, { Set<Key> mostValuableKeys }) {
+  static void push(BuildContext context, Route route) {
     openTransaction(context, (NavigatorTransaction transaction) {
-      transaction.push(route, mostValuableKeys: mostValuableKeys);
+      transaction.push(route);
     });
   }
 
@@ -136,7 +136,7 @@
     });
     return returnValue;
   }
- 
+
   static void popUntil(BuildContext context, Route targetRoute) {
     openTransaction(context, (NavigatorTransaction transaction) {
       transaction.popUntil(targetRoute);
@@ -171,7 +171,7 @@
     super.initState();
     assert(config.observer == null || config.observer.navigator == null);
     config.observer?._navigator = this;
-    _push(config.onGenerateRoute(new NamedRouteSettings(
+    _push(config.onGenerateRoute(new RouteSettings(
       name: config.initialRoute ?? Navigator.defaultRouteName,
       isInitialRoute: true
     )));
@@ -213,7 +213,7 @@
   void _pushNamed(String name, { Set<Key> mostValuableKeys }) {
     assert(!_debugLocked);
     assert(name != null);
-    NamedRouteSettings settings = new NamedRouteSettings(
+    RouteSettings settings = new RouteSettings(
       name: name,
       mostValuableKeys: mostValuableKeys
     );
@@ -226,7 +226,7 @@
     _push(route);
   }
 
-  void _push(Route route, { Set<Key> mostValuableKeys }) {
+  void _push(Route route) {
     assert(!_debugLocked);
     assert(() { _debugLocked = true; return true; });
     assert(route != null);
@@ -388,9 +388,9 @@
   /// The route will have didPush() and didChangeNext() called on it; the
   /// previous route, if any, will have didChangeNext() called on it; and the
   /// Navigator observer, if any, will have didPush() called on it.
-  void push(Route route, { Set<Key> mostValuableKeys }) {
+  void push(Route route) {
     assert(_debugOpen);
-    _navigator._push(route, mostValuableKeys: mostValuableKeys);
+    _navigator._push(route);
   }
 
   /// Replaces one given route with another. Calls install(), didReplace(), and
diff --git a/packages/flutter/lib/src/widgets/pages.dart b/packages/flutter/lib/src/widgets/pages.dart
index 409965c..6fcabc9 100644
--- a/packages/flutter/lib/src/widgets/pages.dart
+++ b/packages/flutter/lib/src/widgets/pages.dart
@@ -14,7 +14,7 @@
 abstract class PageRoute<T> extends ModalRoute<T> {
   PageRoute({
     Completer<T> completer,
-    NamedRouteSettings settings: const NamedRouteSettings()
+    RouteSettings settings: const RouteSettings()
   }) : super(completer: completer, settings: settings);
   bool get opaque => true;
   bool get barrierDismissable => false;
diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart
index f805324..d83afd2 100644
--- a/packages/flutter/lib/src/widgets/routes.dart
+++ b/packages/flutter/lib/src/widgets/routes.dart
@@ -366,12 +366,12 @@
 abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T> {
   ModalRoute({
     Completer<T> completer,
-    this.settings: const NamedRouteSettings()
+    this.settings: const RouteSettings()
   }) : super.explicit(completer, null);
 
   // The API for general users of this class
 
-  final NamedRouteSettings settings;
+  final RouteSettings settings;
 
   static ModalRoute of(BuildContext context) {
     _ModalScopeStatus widget = context.inheritFromWidgetOfType(_ModalScopeStatus);
diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart
index fc92721..f2e6f32 100644
--- a/packages/flutter/lib/widgets.dart
+++ b/packages/flutter/lib/widgets.dart
@@ -12,7 +12,6 @@
 export 'src/widgets/drag_target.dart';
 export 'src/widgets/editable_text.dart';
 export 'src/widgets/enter_exit_transition.dart';
-export 'src/widgets/event_recorder.dart';
 export 'src/widgets/focus.dart';
 export 'src/widgets/framework.dart';
 export 'src/widgets/gesture_detector.dart';
diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml
index ac4d94a..928c89e 100644
--- a/packages/flutter/pubspec.yaml
+++ b/packages/flutter/pubspec.yaml
@@ -7,8 +7,8 @@
   collection: '>=1.1.3 <2.0.0'
   intl: '>=0.12.4+2 <0.13.0'
   material_design_icons: '>=0.0.3 <0.1.0'
-  sky_engine: 0.0.68
-  sky_services: 0.0.68
+  sky_engine: 0.0.69
+  sky_services: 0.0.69
   vector_math: '>=1.4.3 <2.0.0'
 
   # To pin the transitive dependency through mojo_sdk.
diff --git a/packages/unit/test/widget/heroes_test.dart b/packages/unit/test/widget/heroes_test.dart
index c574e65..0ad97c7 100644
--- a/packages/unit/test/widget/heroes_test.dart
+++ b/packages/unit/test/widget/heroes_test.dart
@@ -10,13 +10,15 @@
 
 Key firstKey = new Key('first');
 Key secondKey = new Key('second');
+Key thirdKey = new Key('third');
+
 final Map<String, RouteBuilder> routes = <String, RouteBuilder>{
   '/': (RouteArguments args) => new Material(
     child: new Block([
       new Container(height: 100.0, width: 100.0),
       new Card(child: new Hero(tag: 'a', child: new Container(height: 100.0, width: 100.0, key: firstKey))),
       new Container(height: 100.0, width: 100.0),
-      new FlatButton(child: new Text('button'), onPressed: () => Navigator.pushNamed(args.context, '/two')),
+      new FlatButton(child: new Text('two'), onPressed: () => Navigator.pushNamed(args.context, '/two')),
     ])
   ),
   '/two': (RouteArguments args) => new Material(
@@ -24,11 +26,23 @@
       new Container(height: 150.0, width: 150.0),
       new Card(child: new Hero(tag: 'a', child: new Container(height: 150.0, width: 150.0, key: secondKey))),
       new Container(height: 150.0, width: 150.0),
-      new FlatButton(child: new Text('button'), onPressed: () => Navigator.pop(args.context)),
+      new FlatButton(child: new Text('three'), onPressed: () => Navigator.push(args.context, new ThreeRoute())),
     ])
   ),
 };
 
+class ThreeRoute extends MaterialPageRoute {
+  ThreeRoute() : super(builder: (BuildContext context) {
+    return new Material(
+      child: new Block([
+        new Container(height: 200.0, width: 200.0),
+        new Card(child: new Hero(tag: 'a', child: new Container(height: 200.0, width: 200.0, key: thirdKey))),
+        new Container(height: 200.0, width: 200.0),
+      ])
+    );
+  });
+}
+
 void main() {
   test('Heroes animate', () {
     testWidgets((WidgetTester tester) {
@@ -41,7 +55,7 @@
       expect(tester.findElementByKey(firstKey), isInCard);
       expect(tester.findElementByKey(secondKey), isNull);
 
-      tester.tap(tester.findText('button'));
+      tester.tap(tester.findText('two'));
       tester.pump(); // begin navigation
 
       // at this stage, the second route is off-stage, so that we can form the
@@ -86,6 +100,52 @@
       expect(tester.findElementByKey(secondKey), isOnStage);
       expect(tester.findElementByKey(secondKey), isInCard);
 
+      // Now move on to view 3
+
+      tester.tap(tester.findText('three'));
+      tester.pump(); // begin navigation
+
+      // at this stage, the second route is off-stage, so that we can form the
+      // hero party.
+
+      expect(tester.findElementByKey(secondKey), isOnStage);
+      expect(tester.findElementByKey(secondKey), isInCard);
+      expect(tester.findElementByKey(thirdKey), isOffStage);
+      expect(tester.findElementByKey(thirdKey), isInCard);
+
+      tester.pump();
+
+      // at this stage, the heroes have just gone on their journey, we are
+      // seeing them at t=16ms. The original page no longer contains the hero.
+
+      expect(tester.findElementByKey(secondKey), isNull);
+      expect(tester.findElementByKey(thirdKey), isOnStage);
+      expect(tester.findElementByKey(thirdKey), isNotInCard);
+
+      tester.pump();
+
+      // t=32ms for the journey. Surely they are still at it.
+
+      expect(tester.findElementByKey(secondKey), isNull);
+      expect(tester.findElementByKey(thirdKey), isOnStage);
+      expect(tester.findElementByKey(thirdKey), isNotInCard);
+
+      tester.pump(new Duration(seconds: 1));
+
+      // t=1.032s for the journey. The journey has ended (it ends this frame, in
+      // fact). The hero should now be in the new page, on-stage.
+
+      expect(tester.findElementByKey(secondKey), isNull);
+      expect(tester.findElementByKey(thirdKey), isOnStage);
+      expect(tester.findElementByKey(thirdKey), isInCard);
+
+      tester.pump();
+
+      // Should not change anything.
+
+      expect(tester.findElementByKey(secondKey), isNull);
+      expect(tester.findElementByKey(thirdKey), isOnStage);
+      expect(tester.findElementByKey(thirdKey), isInCard);
     });
   });
 }
diff --git a/packages/unit/test/widget/page_forward_transitions_test.dart b/packages/unit/test/widget/page_forward_transitions_test.dart
index 468289e..b92be39 100644
--- a/packages/unit/test/widget/page_forward_transitions_test.dart
+++ b/packages/unit/test/widget/page_forward_transitions_test.dart
@@ -28,7 +28,7 @@
 }
 
 class TestRoute<T> extends PageRoute<T> {
-  TestRoute({ this.child, NamedRouteSettings settings}) : super(settings: settings);
+  TestRoute({ this.child, RouteSettings settings}) : super(settings: settings);
   final Widget child;
   Duration get transitionDuration => kMaterialPageRouteTransitionDuration;
   Color get barrierColor => null;
@@ -67,7 +67,7 @@
 
       tester.pumpWidget(
         new MaterialApp(
-          onGenerateRoute: (NamedRouteSettings settings) {
+          onGenerateRoute: (RouteSettings settings) {
             switch (settings.name) {
               case '/':
                 return new TestRoute(
diff --git a/packages/unit/test/widget/remember_scroll_position_test.dart b/packages/unit/test/widget/remember_scroll_position_test.dart
index 799ddbc..a225b07 100644
--- a/packages/unit/test/widget/remember_scroll_position_test.dart
+++ b/packages/unit/test/widget/remember_scroll_position_test.dart
@@ -33,7 +33,7 @@
       GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
       tester.pumpWidget(new Navigator(
         key: navigatorKey,
-        onGenerateRoute: (NamedRouteSettings settings) {
+        onGenerateRoute: (RouteSettings settings) {
           if (settings.name == '/')
             return new MaterialPageRoute(builder: (_) => new Container(child: new ThePositiveNumbers()));
           else if (settings.name == '/second')