Merge pull request #1786 from chinmaygarde/master

Explicitly specify the sdk and arch when building for an iOS device
diff --git a/examples/fitness/lib/main.dart b/examples/fitness/lib/main.dart
index c44d54a..90f1b18 100644
--- a/examples/fitness/lib/main.dart
+++ b/examples/fitness/lib/main.dart
@@ -6,7 +6,6 @@
 
 import 'package:playfair/playfair.dart' as playfair;
 import 'package:flutter/material.dart';
-import 'package:flutter/painting.dart';
 import 'package:gcm/gcm.dart' as gcm;
 
 import 'user_data.dart';
diff --git a/examples/fitness/lib/meal.dart b/examples/fitness/lib/meal.dart
index 25deb9f..87f9b03 100644
--- a/examples/fitness/lib/meal.dart
+++ b/examples/fitness/lib/meal.dart
@@ -51,10 +51,10 @@
 }
 
 class MealFragmentState extends State<MealFragment> {
-  String _description = "";
+  InputValue _description = InputValue.empty;
 
   void _handleSave() {
-    config.onCreated(new Meal(when: new DateTime.now(), description: _description));
+    config.onCreated(new Meal(when: new DateTime.now(), description: _description.text));
     Navigator.pop(context);
   }
 
@@ -75,7 +75,7 @@
     );
   }
 
-  void _handleDescriptionChanged(String description) {
+  void _handleDescriptionChanged(InputValue description) {
     setState(() {
       _description = description;
     });
diff --git a/examples/fitness/lib/measurement.dart b/examples/fitness/lib/measurement.dart
index cabce29..ba3f5f5 100644
--- a/examples/fitness/lib/measurement.dart
+++ b/examples/fitness/lib/measurement.dart
@@ -63,13 +63,13 @@
 }
 
 class MeasurementFragmentState extends State<MeasurementFragment> {
-  String _weight = "";
+  InputValue _weight = InputValue.empty;
   DateTime _when = new DateTime.now();
 
   void _handleSave() {
     double parsedWeight;
     try {
-      parsedWeight = double.parse(_weight);
+      parsedWeight = double.parse(_weight.text);
     } on FormatException catch(e) {
       print("Exception $e");
       Scaffold.of(context).showSnackBar(new SnackBar(
@@ -97,7 +97,7 @@
     );
   }
 
-  void _handleWeightChanged(String weight) {
+  void _handleWeightChanged(InputValue weight) {
     setState(() {
       _weight = weight;
     });
diff --git a/examples/fitness/lib/settings.dart b/examples/fitness/lib/settings.dart
index 7d3e6bf..ad12956 100644
--- a/examples/fitness/lib/settings.dart
+++ b/examples/fitness/lib/settings.dart
@@ -4,6 +4,64 @@
 
 part of fitness;
 
+class _SettingsDialog extends StatefulComponent {
+  _SettingsDialogState createState() => new _SettingsDialogState();
+}
+
+class _SettingsDialogState extends State<_SettingsDialog> {
+  final GlobalKey weightGoalKey = new GlobalKey();
+
+  InputValue _goalWeight = InputValue.empty;
+
+  void _handleGoalWeightChanged(InputValue goalWeight) {
+    setState(() {
+      _goalWeight = goalWeight;
+    });
+  }
+
+  void _handleGoalWeightSubmitted(InputValue goalWeight) {
+    _goalWeight = goalWeight;
+    _handleSavePressed();
+  }
+
+  void _handleSavePressed() {
+    double goalWeight;
+    try {
+      goalWeight = double.parse(_goalWeight.text);
+    } on FormatException {
+      goalWeight = 0.0;
+    }
+    Navigator.pop(context, goalWeight);
+  }
+
+  Widget build(BuildContext context) {
+    return new Dialog(
+      title: new Text("Goal Weight"),
+      content: new Input(
+        key: weightGoalKey,
+        value: _goalWeight,
+        autofocus: true,
+        hintText: 'Goal weight in lbs',
+        keyboardType: KeyboardType.number,
+        onChanged: _handleGoalWeightChanged,
+        onSubmitted: _handleGoalWeightSubmitted
+      ),
+      actions: <Widget>[
+        new FlatButton(
+          child: new Text('CANCEL'),
+          onPressed: () {
+            Navigator.pop(context);
+          }
+        ),
+        new FlatButton(
+          child: new Text('SAVE'),
+          onPressed: _handleSavePressed
+        ),
+      ]
+    );
+  }
+}
+
 typedef void SettingsUpdater({
   BackupMode backup,
   double goalWeight
@@ -36,52 +94,10 @@
     return "${config.userData.goalWeight}";
   }
 
-  static final GlobalKey weightGoalKey = new GlobalKey();
-
-  double _goalWeight;
-
-  void _handleGoalWeightChanged(String goalWeight) {
-    // TODO(jackson): Looking for null characters to detect enter key is a hack
-    if (goalWeight.endsWith("\u{0}")) {
-      Navigator.pop(context, double.parse(goalWeight.replaceAll("\u{0}", "")));
-    } else {
-      setState(() {
-        try {
-          _goalWeight = double.parse(goalWeight);
-        } on FormatException {
-          _goalWeight = 0.0;
-        }
-      });
-    }
-  }
-
   Future _handleGoalWeightPressed() async {
     double goalWeight = await showDialog(
       context: context,
-      child: new Dialog(
-        title: new Text("Goal Weight"),
-        content: new Input(
-          key: weightGoalKey,
-          autofocus: true,
-          hintText: 'Goal weight in lbs',
-          keyboardType: KeyboardType.number,
-          onChanged: _handleGoalWeightChanged
-        ),
-        actions: <Widget>[
-          new FlatButton(
-            child: new Text('CANCEL'),
-            onPressed: () {
-              Navigator.pop(context);
-            }
-          ),
-          new FlatButton(
-            child: new Text('SAVE'),
-            onPressed: () {
-              Navigator.pop(context, _goalWeight);
-            }
-          ),
-        ]
-      )
+      child: new _SettingsDialog()
     );
     config.updater(goalWeight: goalWeight);
   }
diff --git a/examples/material_gallery/lib/demo/progress_indicator_demo.dart b/examples/material_gallery/lib/demo/progress_indicator_demo.dart
index 9babb5f..1b5337d 100644
--- a/examples/material_gallery/lib/demo/progress_indicator_demo.dart
+++ b/examples/material_gallery/lib/demo/progress_indicator_demo.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/material.dart';
 
 class ProgressIndicatorDemo extends StatefulComponent {
diff --git a/examples/material_gallery/lib/demo/weathers_demo.dart b/examples/material_gallery/lib/demo/weathers_demo.dart
index a69aa29..2613678 100644
--- a/examples/material_gallery/lib/demo/weathers_demo.dart
+++ b/examples/material_gallery/lib/demo/weathers_demo.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image;
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_sprites/flutter_sprites.dart';
diff --git a/examples/mine_digger/lib/main.dart b/examples/mine_digger/lib/main.dart
index b059934..11ef19d 100644
--- a/examples/mine_digger/lib/main.dart
+++ b/examples/mine_digger/lib/main.dart
@@ -3,10 +3,7 @@
 
 import 'dart:math';
 
-import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/services.dart';
 
 // Classic minesweeper-inspired game. The mouse controls are standard
diff --git a/examples/rendering/baseline.dart b/examples/rendering/baseline.dart
index 2e5163e..2a7a597 100644
--- a/examples/rendering/baseline.dart
+++ b/examples/rendering/baseline.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/rendering.dart';
 
 class _BaselinePainter extends CustomPainter {
@@ -29,7 +27,7 @@
     path.lineTo(w, h);
     paint = new Paint()
      ..color = const Color(0xFFFF9000)
-     ..style = ui.PaintingStyle.stroke
+     ..style = PaintingStyle.stroke
      ..strokeWidth = 1.5;
     canvas.drawPath(path, paint);
 
@@ -39,7 +37,7 @@
     path.lineTo(w, baseline);
     paint = new Paint()
      ..color = const Color(0xFF00FF90)
-     ..style = ui.PaintingStyle.stroke
+     ..style = PaintingStyle.stroke
      ..strokeWidth = 1.5;
     canvas.drawPath(path, paint);
   }
diff --git a/examples/rendering/borders.dart b/examples/rendering/borders.dart
index c6aee48..019f991 100644
--- a/examples/rendering/borders.dart
+++ b/examples/rendering/borders.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/rendering.dart';
 
 void main() {
@@ -15,7 +13,7 @@
           additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
           child: new RenderDecoratedBox(
             decoration: new BoxDecoration(
-              backgroundColor: new ui.Color(0xFFFFFF00)
+              backgroundColor: const Color(0xFFFFFF00)
             )
           )
         )
@@ -27,12 +25,12 @@
           child: new RenderDecoratedBox(
             decoration: new BoxDecoration(
               border: new Border(
-                top: new BorderSide(color: new ui.Color(0xFFF00000), width: 5.0),
-                right: new BorderSide(color: new ui.Color(0xFFFF9000), width: 10.0),
-                bottom: new BorderSide(color: new ui.Color(0xFFFFF000), width: 15.0),
-                left: new BorderSide(color: new ui.Color(0xFF00FF00), width: 20.0)
+                top: new BorderSide(color: const Color(0xFFF00000), width: 5.0),
+                right: new BorderSide(color: const Color(0xFFFF9000), width: 10.0),
+                bottom: new BorderSide(color: const Color(0xFFFFF000), width: 15.0),
+                left: new BorderSide(color: const Color(0xFF00FF00), width: 20.0)
               ),
-              backgroundColor: new ui.Color(0xFFDDDDDD)
+              backgroundColor: const Color(0xFFDDDDDD)
             )
           )
         )
@@ -43,7 +41,7 @@
           additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
           child: new RenderDecoratedBox(
             decoration: new BoxDecoration(
-              backgroundColor: new ui.Color(0xFFFFFF00)
+              backgroundColor: const Color(0xFFFFFF00)
             )
           )
         )
@@ -54,7 +52,7 @@
           additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
           child: new RenderDecoratedBox(
             decoration: new BoxDecoration(
-              backgroundColor: new ui.Color(0xFFFFFF00)
+              backgroundColor: const Color(0xFFFFFF00)
             )
           )
         )
@@ -65,7 +63,7 @@
           additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
           child: new RenderDecoratedBox(
             decoration: new BoxDecoration(
-              backgroundColor: new ui.Color(0xFFFFFF00)
+              backgroundColor: const Color(0xFFFFFF00)
             )
           )
         )
diff --git a/examples/rendering/flex.dart b/examples/rendering/flex.dart
index 8d74e49..270bac3 100644
--- a/examples/rendering/flex.dart
+++ b/examples/rendering/flex.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/rendering.dart';
 import 'lib/solid_color_box.dart';
 
@@ -11,11 +9,11 @@
   RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.vertical);
 
   RenderDecoratedBox root = new RenderDecoratedBox(
-    decoration: new BoxDecoration(backgroundColor: const ui.Color(0xFF000000)),
+    decoration: new BoxDecoration(backgroundColor: const Color(0xFF000000)),
     child: flexRoot
   );
 
-  void addFlexChildSolidColor(RenderFlex parent, ui.Color backgroundColor, { int flex: 0 }) {
+  void addFlexChildSolidColor(RenderFlex parent, Color backgroundColor, { int flex: 0 }) {
     RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
     parent.add(child);
     final FlexParentData childParentData = child.parentData;
@@ -23,13 +21,13 @@
   }
 
   // Yellow bar at top
-  addFlexChildSolidColor(flexRoot, const ui.Color(0xFFFFFF00), flex: 1);
+  addFlexChildSolidColor(flexRoot, const Color(0xFFFFFF00), flex: 1);
 
   // Turquoise box
-  flexRoot.add(new RenderSolidColorBox(const ui.Color(0x7700FFFF), desiredSize: new ui.Size(100.0, 100.0)));
+  flexRoot.add(new RenderSolidColorBox(const Color(0x7700FFFF), desiredSize: new Size(100.0, 100.0)));
 
   var renderDecoratedBlock = new RenderDecoratedBox(
-    decoration: new BoxDecoration(backgroundColor: const ui.Color(0xFFFFFFFF))
+    decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF))
   );
 
   flexRoot.add(new RenderPadding(padding: const EdgeDims.all(10.0), child: renderDecoratedBlock));
@@ -37,11 +35,11 @@
   var row = new RenderFlex(direction: FlexDirection.horizontal);
 
   // Purple and blue cells
-  addFlexChildSolidColor(row, const ui.Color(0x77FF00FF), flex: 1);
-  addFlexChildSolidColor(row, const ui.Color(0xFF0000FF), flex: 2);
+  addFlexChildSolidColor(row, const Color(0x77FF00FF), flex: 1);
+  addFlexChildSolidColor(row, const Color(0xFF0000FF), flex: 2);
 
   var decoratedRow = new RenderDecoratedBox(
-    decoration: new BoxDecoration(backgroundColor: const ui.Color(0xFF333333)),
+    decoration: new BoxDecoration(backgroundColor: const Color(0xFF333333)),
     child: row
   );
 
diff --git a/examples/rendering/interactive_flex.dart b/examples/rendering/interactive_flex.dart
index 7532f28..b93fde2 100644
--- a/examples/rendering/interactive_flex.dart
+++ b/examples/rendering/interactive_flex.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image, window;
 import 'dart:math' as math;
 import 'dart:typed_data';
 
diff --git a/examples/rendering/spinning_flex.dart b/examples/rendering/spinning_flex.dart
index 7557f59..2a100bc 100644
--- a/examples/rendering/spinning_flex.dart
+++ b/examples/rendering/spinning_flex.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/rendering.dart';
 
 import 'lib/solid_color_box.dart';
@@ -14,16 +12,16 @@
 void main() {
   RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.vertical);
 
-  void addFlexChildSolidColor(RenderFlex parent, ui.Color backgroundColor, { int flex: 0 }) {
+  void addFlexChildSolidColor(RenderFlex parent, Color backgroundColor, { int flex: 0 }) {
     RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
     parent.add(child);
     final FlexParentData childParentData = child.parentData;
     childParentData.flex = flex;
   }
 
-  addFlexChildSolidColor(flexRoot, const ui.Color(0xFFFF00FF), flex: 1);
-  addFlexChildSolidColor(flexRoot, const ui.Color(0xFFFFFF00), flex: 2);
-  addFlexChildSolidColor(flexRoot, const ui.Color(0xFF00FFFF), flex: 1);
+  addFlexChildSolidColor(flexRoot, const Color(0xFFFF00FF), flex: 1);
+  addFlexChildSolidColor(flexRoot, const Color(0xFFFFFF00), flex: 2);
+  addFlexChildSolidColor(flexRoot, const Color(0xFF00FFFF), flex: 1);
 
   transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity());
 
diff --git a/examples/rendering/transform.dart b/examples/rendering/transform.dart
index 6a14514..4a4d7f7 100644
--- a/examples/rendering/transform.dart
+++ b/examples/rendering/transform.dart
@@ -2,16 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/rendering.dart';
 
 void main() {
   RenderDecoratedBox green = new RenderDecoratedBox(
-    decoration: new BoxDecoration(backgroundColor: const ui.Color(0xFF00FF00))
+    decoration: new BoxDecoration(backgroundColor: const Color(0xFF00FF00))
   );
   RenderConstrainedBox box = new RenderConstrainedBox(
-    additionalConstraints: new BoxConstraints.tight(const ui.Size(200.0, 200.0)),
+    additionalConstraints: new BoxConstraints.tight(const Size(200.0, 200.0)),
     child: green
   );
 
diff --git a/examples/stocks/lib/main.dart b/examples/stocks/lib/main.dart
index 38fe498..c342b4e 100644
--- a/examples/stocks/lib/main.dart
+++ b/examples/stocks/lib/main.dart
@@ -5,29 +5,18 @@
 library stocks;
 
 import 'dart:async';
-import 'dart:collection';
-import 'dart:math' as math;
-import 'dart:ui' as ui;
 
-import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
-import 'package:flutter/scheduler.dart';
+import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
 import 'package:intl/intl.dart';
 
-import 'stock_data.dart';
 import 'i18n/stock_messages_all.dart';
-
-part 'stock_arrow.dart';
-part 'stock_home.dart';
-part 'stock_list.dart';
-part 'stock_menu.dart';
-part 'stock_row.dart';
-part 'stock_settings.dart';
-part 'stock_strings.dart';
-part 'stock_symbol_viewer.dart';
-part 'stock_types.dart';
+import 'stock_data.dart';
+import 'stock_home.dart';
+import 'stock_settings.dart';
+import 'stock_strings.dart';
+import 'stock_symbol_viewer.dart';
+import 'stock_types.dart';
 
 class StocksApp extends StatefulComponent {
   StocksAppState createState() => new StocksAppState();
@@ -94,7 +83,7 @@
     return null;
   }
 
-  Future<LocaleQueryData> _onLocaleChanged(ui.Locale locale) async {
+  Future<LocaleQueryData> _onLocaleChanged(Locale locale) async {
     String localeString = locale.toString();
     await initializeMessages(localeString);
     Intl.defaultLocale = localeString;
diff --git a/examples/stocks/lib/stock_arrow.dart b/examples/stocks/lib/stock_arrow.dart
index 142d6f6..67f0203 100644
--- a/examples/stocks/lib/stock_arrow.dart
+++ b/examples/stocks/lib/stock_arrow.dart
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'dart:math' as math;
+
+import 'package:flutter/material.dart';
 
 class StockArrowPainter extends CustomPainter {
   StockArrowPainter({ this.color, this.percentChange });
@@ -34,11 +36,11 @@
     path.lineTo(centerX + w, arrowY + h);
     path.lineTo(centerX - w, arrowY + h);
     path.close();
-    paint.style = ui.PaintingStyle.fill;
+    paint.style = PaintingStyle.fill;
     canvas.drawPath(path, paint);
 
     // Draw a circle that circumscribes the arrow.
-    paint.style = ui.PaintingStyle.stroke;
+    paint.style = PaintingStyle.stroke;
     canvas.drawCircle(new Point(centerX, centerY), r, paint);
   }
 
diff --git a/examples/stocks/lib/stock_home.dart b/examples/stocks/lib/stock_home.dart
index 81c93c6..7b4734ce 100644
--- a/examples/stocks/lib/stock_home.dart
+++ b/examples/stocks/lib/stock_home.dart
@@ -2,7 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'dart:collection';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart' show debugDumpRenderTree, debugDumpLayerTree, debugDumpSemanticsTree;
+
+import 'stock_data.dart';
+import 'stock_list.dart';
+import 'stock_menu.dart';
+import 'stock_strings.dart';
+import 'stock_symbol_viewer.dart';
+import 'stock_types.dart';
 
 typedef void ModeUpdater(StockMode mode);
 
@@ -23,14 +33,14 @@
 
   final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
   bool _isSearching = false;
-  String _searchQuery;
+  InputValue _searchQuery = InputValue.empty;
 
   void _handleSearchBegin() {
     ModalRoute.of(context).addLocalHistoryEntry(new LocalHistoryEntry(
       onRemove: () {
         setState(() {
           _isSearching = false;
-          _searchQuery = null;
+          _searchQuery = InputValue.empty;
         });
       }
     ));
@@ -43,7 +53,7 @@
     Navigator.pop(context);
   }
 
-  void _handleSearchQueryChanged(String query) {
+  void _handleSearchQueryChanged(InputValue query) {
     setState(() {
       _searchQuery = query;
     });
@@ -187,9 +197,9 @@
   }
 
   Iterable<Stock> _filterBySearchQuery(Iterable<Stock> stocks) {
-    if (_searchQuery == null)
+    if (_searchQuery.text.isEmpty)
       return stocks;
-    RegExp regexp = new RegExp(_searchQuery, caseSensitive: false);
+    RegExp regexp = new RegExp(_searchQuery.text, caseSensitive: false);
     return stocks.where((Stock stock) => stock.symbol.contains(regexp));
   }
 
@@ -244,6 +254,7 @@
         tooltip: 'Back'
       ),
       center: new Input(
+        value: _searchQuery,
         key: searchFieldKey,
         autofocus: true,
         hintText: 'Search stocks',
diff --git a/examples/stocks/lib/stock_list.dart b/examples/stocks/lib/stock_list.dart
index 19fae3e..153db69 100644
--- a/examples/stocks/lib/stock_list.dart
+++ b/examples/stocks/lib/stock_list.dart
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'package:flutter/material.dart';
+
+import 'stock_data.dart';
+import 'stock_row.dart';
 
 class StockList extends StatelessComponent {
   StockList({ Key key, this.keySalt, this.stocks, this.onOpen, this.onShow, this.onAction }) : super(key: key);
diff --git a/examples/stocks/lib/stock_menu.dart b/examples/stocks/lib/stock_menu.dart
index ed515c7..065d0d4 100644
--- a/examples/stocks/lib/stock_menu.dart
+++ b/examples/stocks/lib/stock_menu.dart
@@ -2,7 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'dart:async';
+import 'dart:ui' as ui show window;
+
+import 'package:flutter/material.dart';
+import 'package:flutter/scheduler.dart' show timeDilation;
 
 enum _MenuItems { autorefresh, autorefreshCheckbox, refresh, speedUp, speedDown }
 
diff --git a/examples/stocks/lib/stock_row.dart b/examples/stocks/lib/stock_row.dart
index 5c7e329..40a7399 100644
--- a/examples/stocks/lib/stock_row.dart
+++ b/examples/stocks/lib/stock_row.dart
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'package:flutter/material.dart';
+
+import 'stock_data.dart';
+import 'stock_arrow.dart';
 
 enum StockRowPartKind { arrow }
 
diff --git a/examples/stocks/lib/stock_settings.dart b/examples/stocks/lib/stock_settings.dart
index eea7e09..2cfcd54 100644
--- a/examples/stocks/lib/stock_settings.dart
+++ b/examples/stocks/lib/stock_settings.dart
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'package:flutter/material.dart';
+
+import 'stock_types.dart';
 
 class StockSettings extends StatefulComponent {
   const StockSettings(this.configuration, this.updater);
diff --git a/examples/stocks/lib/stock_strings.dart b/examples/stocks/lib/stock_strings.dart
index e65d1f3..d5c1dc4 100644
--- a/examples/stocks/lib/stock_strings.dart
+++ b/examples/stocks/lib/stock_strings.dart
@@ -1,4 +1,9 @@
-part of stocks;
+// 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:intl/intl.dart';
+import 'package:flutter/widgets.dart';
 
 // Wrappers for strings that are shown in the UI.  The strings can be
 // translated for different locales using the Dart intl package.
diff --git a/examples/stocks/lib/stock_symbol_viewer.dart b/examples/stocks/lib/stock_symbol_viewer.dart
index 92161a0..d718e38 100644
--- a/examples/stocks/lib/stock_symbol_viewer.dart
+++ b/examples/stocks/lib/stock_symbol_viewer.dart
@@ -2,7 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
+import 'package:flutter/material.dart';
+
+import 'stock_data.dart';
+import 'stock_arrow.dart';
+import 'stock_row.dart';
 
 class StockSymbolView extends StatelessComponent {
   StockSymbolView({ this.stock });
diff --git a/examples/stocks/lib/stock_types.dart b/examples/stocks/lib/stock_types.dart
index e65eff4..2aa8394 100644
--- a/examples/stocks/lib/stock_types.dart
+++ b/examples/stocks/lib/stock_types.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of stocks;
-
 enum StockMode { optimistic, pessimistic }
 enum BackupMode { enabled, disabled }
 
diff --git a/examples/widgets/card_collection.dart b/examples/widgets/card_collection.dart
index 3193303..241dee5 100644
--- a/examples/widgets/card_collection.dart
+++ b/examples/widgets/card_collection.dart
@@ -2,20 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/material.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
+import 'package:flutter/rendering.dart' show debugDumpRenderTree;
 
 class CardModel {
   CardModel(this.value, this.height) {
-    label = "Item $value";
+    inputValue = new InputValue(text: "Item $value");
   }
   int value;
   double height;
   int get color => ((value % 9) + 1) * 100;
-  String label;
+  InputValue inputValue;
   Key get key => new ObjectKey(this);
 }
 
@@ -308,9 +305,11 @@
             new Center(
               child: new Input(
                 key: new GlobalObjectKey(cardModel),
-                initialValue: cardModel.label,
-                onChanged: (String value) {
-                  cardModel.label = value;
+                value: cardModel.inputValue,
+                onChanged: (InputValue value) {
+                  setState(() {
+                    cardModel.inputValue = value;
+                  });
                 }
               )
             )
@@ -320,7 +319,7 @@
               ),
               child: new Column(
                 children: <Widget>[
-                  new Text(cardModel.label)
+                  new Text(cardModel.inputValue.text)
                 ],
                 alignItems: FlexAlignItems.stretch,
                 justifyContent: FlexJustifyContent.center
@@ -394,7 +393,7 @@
     });
   }
 
-  ui.Shader _createShader(Rect bounds) {
+  Shader _createShader(Rect bounds) {
     return new LinearGradient(
         begin: bounds.topLeft,
         end: bounds.bottomLeft,
diff --git a/examples/widgets/custom_render_box.dart b/examples/widgets/custom_render_box.dart
new file mode 100644
index 0000000..d5bb2f5
--- /dev/null
+++ b/examples/widgets/custom_render_box.dart
@@ -0,0 +1,42 @@
+// 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/rendering.dart';
+import 'package:flutter/widgets.dart';
+
+class _CustomRenderBox extends RenderConstrainedBox {
+  _CustomRenderBox() : super(additionalConstraints: const BoxConstraints.expand());
+
+  // Makes this render box hittable so that we'll get pointer events.
+  bool hitTestSelf(Point position) => true;
+
+  final Map<int, Point> _dots = <int, Point>{};
+
+  void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
+    if (event is PointerDownEvent || event is PointerMoveEvent) {
+      _dots[event.pointer] = event.position;
+      markNeedsPaint();
+    } else if (event is PointerUpEvent || event is PointerCancelEvent) {
+      _dots.remove(event.pointer);
+      markNeedsPaint();
+    }
+  }
+
+  void paint(PaintingContext context, Offset offset) {
+    final Canvas canvas = context.canvas;
+    canvas.drawRect(offset & size, new Paint()..color = new Color(0xFF00FF00));
+
+    Paint paint = new Paint()..color = new Color(0xFF0000FF);
+    for (Point point in _dots.values)
+      canvas.drawCircle(point, 50.0, paint);
+  }
+}
+
+class _CustomRenderBoxWidget extends OneChildRenderObjectWidget {
+  _CustomRenderBox createRenderObject() => new _CustomRenderBox();
+}
+
+void main() {
+  runApp(new _CustomRenderBoxWidget());
+}
diff --git a/examples/widgets/drag_and_drop.dart b/examples/widgets/drag_and_drop.dart
index 2e72edd..2256a79 100644
--- a/examples/widgets/drag_and_drop.dart
+++ b/examples/widgets/drag_and_drop.dart
@@ -3,11 +3,8 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
 
 import 'package:flutter/material.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
 
 class ExampleDragTarget extends StatefulComponent {
   ExampleDragTargetState createState() => new ExampleDragTargetState();
@@ -42,20 +39,29 @@
   }
 }
 
-class Dot extends StatelessComponent {
-  Dot({ Key key, this.color, this.size, this.child }) : super(key: key);
+class Dot extends StatefulComponent {
+  Dot({ Key key, this.color, this.size, this.child, this.tappable: false }) : super(key: key);
   final Color color;
   final double size;
   final Widget child;
+  final bool tappable;
+  DotState createState() => new DotState();
+}
+class DotState extends State<Dot> {
+  int taps = 0;
   Widget build(BuildContext context) {
-    return new Container(
-      width: size,
-      height: size,
-      decoration: new BoxDecoration(
-        backgroundColor: color,
-        shape: BoxShape.circle
-      ),
-      child: child
+    return new GestureDetector(
+      onTap: config.tappable ? () { setState(() { taps += 1; }); } : null,
+      child: new Container(
+        width: config.size,
+        height: config.size,
+        decoration: new BoxDecoration(
+          backgroundColor: config.color,
+          border: new Border.all(color: const Color(0xFF000000), width: taps.toDouble()),
+          shape: BoxShape.circle
+        ),
+        child: config.child
+      )
     );
   }
 }
@@ -144,7 +150,7 @@
     final double radius = size.shortestSide / 2.0;
     final Paint paint = new Paint()
       ..color = const Color(0xFF000000)
-      ..style = ui.PaintingStyle.stroke
+      ..style = PaintingStyle.stroke
       ..strokeWidth = radius / 10.0;
     final Path path = new Path();
     final Rect box = Point.origin & size;
@@ -158,10 +164,14 @@
 
 class MovableBall extends StatelessComponent {
   MovableBall(this.position, this.ballPosition, this.callback);
+
   final int position;
   final int ballPosition;
   final ValueChanged<int> callback;
+
+  static final GlobalKey kBallKey = new GlobalKey();
   static const double kBallSize = 50.0;
+
   Widget build(BuildContext context) {
     Widget ball = new DefaultTextStyle(
       style: Theme.of(context).text.body1.copyWith(
@@ -169,8 +179,10 @@
         color: Colors.white
       ),
       child: new Dot(
+        key: kBallKey,
         color: Colors.blue[700],
         size: kBallSize,
+        tappable: true,
         child: new Center(child: new Text('BALL'))
       )
     );
diff --git a/examples/widgets/hero_under.dart b/examples/widgets/hero_under.dart
index 1177f1d..1c1b5bc 100644
--- a/examples/widgets/hero_under.dart
+++ b/examples/widgets/hero_under.dart
@@ -2,7 +2,7 @@
 // for details. 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:ui' as ui;
+import 'dart:ui' as ui show window;
 
 import 'package:flutter/widgets.dart';
 import 'package:flutter/material.dart';
diff --git a/examples/widgets/mimic_demo.dart b/examples/widgets/mimic_demo.dart
index a901bb4..3ce73c8 100644
--- a/examples/widgets/mimic_demo.dart
+++ b/examples/widgets/mimic_demo.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/material.dart';
 
 const double _kHeight = 150.0;
diff --git a/examples/widgets/nine_patch.dart b/examples/widgets/nine_patch.dart
index f0faf2c..073070a 100644
--- a/examples/widgets/nine_patch.dart
+++ b/examples/widgets/nine_patch.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/painting.dart';
 import 'package:flutter/material.dart';
 
 void main() {
diff --git a/examples/widgets/overlay_geometry.dart b/examples/widgets/overlay_geometry.dart
index fed1bfa..74e0545 100644
--- a/examples/widgets/overlay_geometry.dart
+++ b/examples/widgets/overlay_geometry.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
@@ -36,7 +34,7 @@
 
     paint
       ..color = const Color(0xFFFFFFFF)
-      ..style = ui.PaintingStyle.stroke
+      ..style = PaintingStyle.stroke
       ..strokeWidth = 1.0;
     if (type == MarkerType.topLeft) {
       canvas.drawLine(new Point(r, r), new Point(r + r - 1.0, r), paint);
diff --git a/examples/widgets/pageable_list.dart b/examples/widgets/pageable_list.dart
index 5141a91..142c9c6 100644
--- a/examples/widgets/pageable_list.dart
+++ b/examples/widgets/pageable_list.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'package:flutter/material.dart';
-import 'package:flutter/painting.dart';
 
 class CardModel {
   CardModel(this.value, this.size, this.color);
diff --git a/examples/widgets/resolution_awareness.dart b/examples/widgets/resolution_awareness.dart
index 888de8f..c98117f 100644
--- a/examples/widgets/resolution_awareness.dart
+++ b/examples/widgets/resolution_awareness.dart
@@ -1,7 +1,8 @@
 // Copyright (c) 2016, the Flutter project authors.  Please see the AUTHORS file
 // for details. 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:ui' as ui;
+
+import 'dart:ui' as ui show window;
 
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
diff --git a/examples/widgets/smooth_resize.dart b/examples/widgets/smooth_resize.dart
index 3788660..347224e 100644
--- a/examples/widgets/smooth_resize.dart
+++ b/examples/widgets/smooth_resize.dart
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
 
 final List<Map<int, Color>> _kColors = <Map<int, Color>>[
   Colors.amber,
diff --git a/examples/widgets/spinning_mixed.dart b/examples/widgets/spinning_mixed.dart
index 4e6d065..b8acb69 100644
--- a/examples/widgets/spinning_mixed.dart
+++ b/examples/widgets/spinning_mixed.dart
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
 
 import 'package:flutter_rendering_examples/solid_color_box.dart';
 
 // Solid colour, RenderObject version
-void addFlexChildSolidColor(RenderFlex parent, ui.Color backgroundColor, { int flex: 0 }) {
+void addFlexChildSolidColor(RenderFlex parent, Color backgroundColor, { int flex: 0 }) {
   RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
   parent.add(child);
   FlexParentData childParentData = child.parentData;
@@ -92,9 +90,9 @@
   attachWidgetTreeToRenderTree(proxy);
 
   RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.vertical);
-  addFlexChildSolidColor(flexRoot, const ui.Color(0xFFFF00FF), flex: 1);
+  addFlexChildSolidColor(flexRoot, const Color(0xFFFF00FF), flex: 1);
   flexRoot.add(proxy);
-  addFlexChildSolidColor(flexRoot, const ui.Color(0xFF0000FF), flex: 1);
+  addFlexChildSolidColor(flexRoot, const Color(0xFF0000FF), flex: 1);
 
   transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity());
   RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox);
diff --git a/infra/README.md b/infra/README.md
index f0e8417..f3e11aa 100644
--- a/infra/README.md
+++ b/infra/README.md
@@ -1,12 +1,59 @@
-Directory to support running Flutter builds/tests on Chromium Infra.
+# Flutter's Build Infrastructure
 
-Following documentation at:
-https://github.com/luci/recipes-py/blob/master/doc/cross_repo.md
+This directory exists to support building Flutter on our build infrastructure.
 
-recipes.cfg is a protobuf dump (no comment support) explaining
-where to store build and recipe_engine dependencies needed for running
-a recipe.
+The results of such builds are viewable at
+https://build.chromium.org/p/client.flutter/waterfall
 
-recipes.py is for bootstrapping and is taken from
-https://chromium.googlesource.com/chromium/tools/build.git/+/master/scripts/slave/recipes.py
-at 18df86c, modified to have correct hard-coded paths for flutter.
+The external master pages do not allow forcing new builds. Contact
+@eseidelGoogle or another member of Google's Flutter team if you need to do
+that.
+
+Our infrastructure is broken into two parts.  A buildbot master specified by our
+[builders.pyl](https://chromium.googlesource.com/chromium/tools/build.git/+/master/masters/master.client.flutter/builders.pyl)
+file, and a [set of
+recipes](https://chromium.googlesource.com/chromium/tools/build.git/+/master/scripts/slave/recipes/flutter)
+which we run on that master.  Both of these technologies are highly specific to
+Google's Chromium project. We're just borrowing some of their infrastructure.
+
+## Editing a recipe
+
+Flutter has one recipe per repository. Currently
+[flutter/flutter](https://chromium.googlesource.com/chromium/tools/build.git/+/master/scripts/slave/recipes/flutter/flutter.py)
+and
+[flutter/engine](https://chromium.googlesource.com/chromium/tools/build.git/+/master/scripts/slave/recipes/flutter/engine.py).
+
+Recipes are just python.  They are
+[documented](https://github.com/luci/recipes-py/blob/master/doc/user_guide.md)
+by the [luci/recipes-py github project](https://github.com/luci/recipes-py).
+
+Most of the functionality for recipes comes from recipe_modules, which are
+unfortunately spread to many separate repositories.  The easiest way to find
+documentation on how to use modules is to [get a full checkout of chromium's
+`infra`
+repositories](https://chromium.googlesource.com/infra/infra/+/master/doc/source.md)
+and search for files named `api.py` or `example.py` under `infra/build`.
+
+## Editing the client.flutter buildbot master
+
+Flutter uses Chromium's fancy
+[builders.pyl](https://chromium.googlesource.com/infra/infra/+/master/doc/users/services/buildbot/builders.pyl.md)
+master generation system.  Chromium hosts 100s (if not 1000s) of buildbot
+masters and thus has lots of infrastructure for turning them up and down.
+Eventually all of buildbot is planned to be replaced by other infrastruture, but
+for now flutter has its own client.flutter master.
+
+You would need to edit client.flutter's master in order to add slaves (talk to
+@eseidelGoogle), add builder groups, or to change the html layout of
+https://build.chromium.org/p/client.flutter.  Carefully follow the [builders.pyl
+docs](https://chromium.googlesource.com/infra/infra/+/master/doc/users/services/buildbot/builders.pyl.md)
+to do so.
+
+## Future Directions
+
+We would like to host our own recipes instead of storing them in
+[build](https://chromium.googlesource.com/chromium/tools/build.git/+/master/scripts/slave/recipes/flutter).
+Support for [cross-repository
+recipes](https://github.com/luci/recipes-py/blob/master/doc/cross_repo.md) is
+in-progress.  If you view the git log of this directory, you'll see we intially
+tried, but it's not quite ready.
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
deleted file mode 100644
index e24c1fd3..0000000
--- a/infra/config/recipes.cfg
+++ /dev/null
@@ -1,15 +0,0 @@
-api_version: 1
-project_id: "flutter"
-recipes_path: "infra"
-deps {
-  project_id: "build"
-  url: "https://chromium.googlesource.com/chromium/tools/build"
-  branch: "master"
-  revision: "7e696f8d7969be66a13a2ad54970a43f2eae930e"
-}
-deps {
-  project_id: "recipe_engine"
-  url: "https://chromium.googlesource.com/external/github.com/luci/recipes-py.git"
-  branch: "master"
-  revision: "636414454465da499a9ea443364eec7b830ed34c"
-}
diff --git a/infra/recipes.py b/infra/recipes.py
deleted file mode 100755
index ccab6db..0000000
--- a/infra/recipes.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python
-
-# 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.
-
-"""Bootstrap script to clone and forward to the recipe engine tool."""
-
-import ast
-import logging
-import os
-import random
-import re
-import subprocess
-import sys
-import time
-import traceback
-
-BOOTSTRAP_VERSION = 1
-# The root of the repository relative to the directory of this file.
-REPO_ROOT = os.path.join(os.pardir)
-# The path of the recipes.cfg file relative to the root of the repository.
-RECIPES_CFG = os.path.join('infra', 'config', 'recipes.cfg')
-
-
-def parse_protobuf(fh):
-  """Parse the protobuf text format just well enough to understand recipes.cfg.
-
-  We don't use the protobuf library because we want to be as self-contained
-  as possible in this bootstrap, so it can be simply vendored into a client
-  repo.
-
-  We assume all fields are repeated since we don't have a proto spec to work
-  with.
-
-  Args:
-    fh: a filehandle containing the text format protobuf.
-  Returns:
-    A recursive dictionary of lists.
-  """
-  def parse_atom(text):
-    if text == 'true': return True
-    if text == 'false': return False
-    return ast.literal_eval(text)
-
-  ret = {}
-  for line in fh:
-    line = line.strip()
-    m = re.match(r'(\w+)\s*:\s*(.*)', line)
-    if m:
-      ret.setdefault(m.group(1), []).append(parse_atom(m.group(2)))
-      continue
-
-    m = re.match(r'(\w+)\s*{', line)
-    if m:
-      subparse = parse_protobuf(fh)
-      ret.setdefault(m.group(1), []).append(subparse)
-      continue
-
-    if line == '}': return ret
-    if line == '': continue
-
-    raise Exception('Could not understand line: <%s>' % line)
-
-  return ret
-
-
-def get_unique(things):
-  if len(things) == 1:
-    return things[0]
-  elif len(things) == 0:
-    raise ValueError("Expected to get one thing, but dinna get none.")
-  else:
-    logging.warn('Expected to get one thing, but got a bunch: %s\n%s' %
-                 (things, traceback.format_stack()))
-    return things[0]
-
-
-def main():
-  if sys.platform.startswith(('win', 'cygwin')):
-    git = 'git.bat'
-  else:
-    git = 'git'
-
-  # Find the repository and config file to operate on.
-  repo_root = os.path.abspath(
-      os.path.join(os.path.dirname(__file__), REPO_ROOT))
-  recipes_cfg_path = os.path.join(repo_root, RECIPES_CFG)
-
-  with open(recipes_cfg_path, 'rU') as fh:
-    protobuf = parse_protobuf(fh)
-
-  engine_buf = get_unique([
-      b for b in protobuf['deps'] if b.get('project_id') == ['recipe_engine'] ])
-  engine_url = get_unique(engine_buf['url'])
-  engine_revision = get_unique(engine_buf['revision'])
-  engine_subpath = (get_unique(engine_buf.get('path_override', ['']))
-                    .replace('/', os.path.sep))
-
-  recipes_path = os.path.join(repo_root,
-      get_unique(protobuf['recipes_path']).replace('/', os.path.sep))
-  deps_path = os.path.join(recipes_path, '.recipe_deps')
-  engine_path = os.path.join(deps_path, 'recipe_engine')
-
-  # Ensure that we have the recipe engine cloned.
-  def ensure_engine():
-    if not os.path.exists(deps_path):
-      os.makedirs(deps_path)
-    if not os.path.exists(engine_path):
-      subprocess.check_call([git, 'clone', engine_url, engine_path])
-
-    needs_fetch = subprocess.call(
-        [git, 'rev-parse', '--verify', '%s^{commit}' % engine_revision],
-        cwd=engine_path, stdout=open(os.devnull, 'w'))
-    if needs_fetch:
-      subprocess.check_call([git, 'fetch'], cwd=engine_path)
-    subprocess.check_call(
-        [git, 'checkout', '--quiet', engine_revision], cwd=engine_path)
-
-  try:
-    ensure_engine()
-  except subprocess.CalledProcessError as e:
-    if e.returncode == 128:  # Thrown when git gets a lock error.
-      time.sleep(random.uniform(2,5))
-      ensure_engine()
-    else:
-      raise
-
-  args = ['--package', recipes_cfg_path,
-          '--bootstrap-script', __file__] + sys.argv[1:]
-  return subprocess.call([
-      sys.executable, '-u',
-      os.path.join(engine_path, engine_subpath, 'recipes.py')] + args)
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/infra/recipes/flutter.expected/basic.json b/infra/recipes/flutter.expected/basic.json
deleted file mode 100644
index 3833e0b..0000000
--- a/infra/recipes/flutter.expected/basic.json
+++ /dev/null
@@ -1,158 +0,0 @@
-[
-  {
-    "cmd": [
-      "python",
-      "-u",
-      "RECIPE_PACKAGE[build]/git_setup.py",
-      "--path",
-      "[SLAVE_BUILD]/flutter",
-      "--url",
-      "https://github.com/flutter/flutter.git"
-    ],
-    "cwd": "[SLAVE_BUILD]",
-    "name": "git setup"
-  },
-  {
-    "cmd": [
-      "git",
-      "retry",
-      "fetch",
-      "origin",
-      "master",
-      "--recurse-submodules"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter",
-    "name": "git fetch"
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter",
-    "name": "git checkout"
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter",
-    "name": "git clean"
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "sync"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter",
-    "name": "submodule sync"
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--init",
-      "--recursive"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter",
-    "name": "submodule update"
-  },
-  {
-    "cmd": [
-      "dart",
-      "[SLAVE_BUILD]/flutter/dev/update_packages.dart"
-    ],
-    "cwd": "[SLAVE_BUILD]",
-    "name": "update packages"
-  },
-  {
-    "cmd": [
-      "[SLAVE_BUILD]/flutter/bin/flutter",
-      "cache",
-      "populate"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/packages/flutter",
-    "name": "populate flutter cache"
-  },
-  {
-    "cmd": [
-      "[SLAVE_BUILD]/flutter/bin/flutter",
-      "analyze",
-      "--flutter-repo",
-      "--no-current-directory",
-      "--no-current-package",
-      "--congratulate"
-    ],
-    "cwd": "[SLAVE_BUILD]",
-    "name": "flutter analyze"
-  },
-  {
-    "cmd": [
-      "pub",
-      "run",
-      "test",
-      "-j1"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/packages/cassowary",
-    "name": "test packages/cassowary"
-  },
-  {
-    "cmd": [
-      "[SLAVE_BUILD]/flutter/bin/flutter",
-      "test"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/packages/flutter",
-    "name": "test packages/flutter"
-  },
-  {
-    "cmd": [
-      "pub",
-      "run",
-      "test",
-      "-j1"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/packages/flutter_tools",
-    "name": "test packages/flutter_tools"
-  },
-  {
-    "cmd": [
-      "pub",
-      "run",
-      "test",
-      "-j1"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/packages/flx",
-    "name": "test packages/flx"
-  },
-  {
-    "cmd": [
-      "pub",
-      "run",
-      "test",
-      "-j1"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/packages/newton",
-    "name": "test packages/newton"
-  },
-  {
-    "cmd": [
-      "[SLAVE_BUILD]/flutter/bin/flutter",
-      "test"
-    ],
-    "cwd": "[SLAVE_BUILD]/flutter/examples/stocks",
-    "name": "test examples/stocks"
-  },
-  {
-    "name": "$result",
-    "recipe_result": null,
-    "status_code": 0
-  }
-]
\ No newline at end of file
diff --git a/infra/recipes/flutter.py b/infra/recipes/flutter.py
deleted file mode 100644
index fd2f887..0000000
--- a/infra/recipes/flutter.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2014 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.
-
-DEPS = [
-  'recipe_engine/path',
-  'recipe_engine/step',
-  'build/git',
-]
-
-def RunSteps(api):
-  api.git.checkout('https://github.com/flutter/flutter.git', recursive=True)
-
-  checkout = api.path['checkout']
-  update_packages = checkout.join('dev', 'update_packages.dart')
-
-  api.step('update packages', ['dart', update_packages])
-
-  flutter_cli = checkout.join('bin', 'flutter')
-  flutter_package = checkout.join('packages', 'flutter')
-  populate_cmd = [flutter_cli, 'cache', 'populate']
-  api.step('populate flutter cache', populate_cmd, cwd=flutter_package)
-
-  analyze_cmd = [
-    flutter_cli,
-    'analyze',
-    '--flutter-repo',
-    '--no-current-directory',
-    '--no-current-package',
-    '--congratulate'
-  ]
-  api.step('flutter analyze', analyze_cmd)
-
-
-  def _pub_test(path):
-    api.step('test %s' % path, ['pub', 'run', 'test', '-j1'],
-      cwd=checkout.join(path))
-
-  def _flutter_test(path):
-    api.step('test %s' % path, [flutter_cli, 'test'],
-      cwd=checkout.join(path))
-
-  _pub_test('packages/cassowary')
-  _flutter_test('packages/flutter')
-  _pub_test('packages/flutter_tools')
-  _pub_test('packages/flx')
-  _pub_test('packages/newton')
-
-  _flutter_test('examples/stocks')
-
-def GenTests(api):
-  yield api.test('basic')
diff --git a/packages/flutter/lib/animation.dart b/packages/flutter/lib/animation.dart
index 7137fc2..c386df3 100644
--- a/packages/flutter/lib/animation.dart
+++ b/packages/flutter/lib/animation.dart
@@ -15,5 +15,4 @@
 export 'src/animation/curves.dart';
 export 'src/animation/forces.dart';
 export 'src/animation/listener_helpers.dart';
-export 'src/animation/ticker.dart';
 export 'src/animation/tween.dart';
diff --git a/packages/flutter/lib/gestures.dart b/packages/flutter/lib/gestures.dart
index 1dce643..67cc881 100644
--- a/packages/flutter/lib/gestures.dart
+++ b/packages/flutter/lib/gestures.dart
@@ -14,6 +14,7 @@
 export 'src/gestures/hit_test.dart';
 export 'src/gestures/long_press.dart';
 export 'src/gestures/lsq_solver.dart';
+export 'src/gestures/multidrag.dart';
 export 'src/gestures/multitap.dart';
 export 'src/gestures/pointer_router.dart';
 export 'src/gestures/recognizer.dart';
diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart
index ca38e5f..7902f6b 100644
--- a/packages/flutter/lib/painting.dart
+++ b/packages/flutter/lib/painting.dart
@@ -17,7 +17,6 @@
 export 'src/painting/colors.dart';
 export 'src/painting/decoration.dart';
 export 'src/painting/edge_dims.dart';
-export 'src/painting/shadows.dart';
 export 'src/painting/text_editing.dart';
 export 'src/painting/text_painter.dart';
 export 'src/painting/text_style.dart';
diff --git a/packages/flutter/lib/scheduler.dart b/packages/flutter/lib/scheduler.dart
index 11e4466..17b3030 100644
--- a/packages/flutter/lib/scheduler.dart
+++ b/packages/flutter/lib/scheduler.dart
@@ -12,3 +12,4 @@
 library scheduler;
 
 export 'src/scheduler/scheduler.dart';
+export 'src/scheduler/ticker.dart';
diff --git a/packages/flutter/lib/src/animation/animation.dart b/packages/flutter/lib/src/animation/animation.dart
index 502a47d..1e89f48 100644
--- a/packages/flutter/lib/src/animation/animation.dart
+++ b/packages/flutter/lib/src/animation/animation.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' show Color, Size, Rect, VoidCallback, lerpDouble;
+import 'dart:ui' show Color, Size, Rect, VoidCallback;
 
 /// The direction in which an animation is running.
 enum AnimationDirection {
diff --git a/packages/flutter/lib/src/animation/animation_controller.dart b/packages/flutter/lib/src/animation/animation_controller.dart
index 3c887d3d..124aa31 100644
--- a/packages/flutter/lib/src/animation/animation_controller.dart
+++ b/packages/flutter/lib/src/animation/animation_controller.dart
@@ -3,15 +3,15 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:ui' show VoidCallback, lerpDouble;
+import 'dart:ui' as ui show lerpDouble;
 
+import 'package:flutter/scheduler.dart';
 import 'package:newton/newton.dart';
 
 import 'animation.dart';
 import 'curves.dart';
 import 'forces.dart';
 import 'listener_helpers.dart';
-import 'ticker.dart';
 
 /// A controller for an animation.
 ///
@@ -20,7 +20,7 @@
 /// bounds of the animation and can drive an animation using a physics
 /// simulation.
 class AnimationController extends Animation<double>
-  with EagerListenerMixin, LocalListenersMixin, LocalAnimationStatusListenersMixin {
+  with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
 
   /// Creates an animation controller.
   ///
@@ -257,7 +257,7 @@
   double x(double timeInSeconds) {
     assert(timeInSeconds >= 0.0);
     final double t = (timeInSeconds / _periodInSeconds) % 1.0;
-    return lerpDouble(min, max, t);
+    return ui.lerpDouble(min, max, t);
   }
 
   double dx(double timeInSeconds) => 1.0;
diff --git a/packages/flutter/lib/src/animation/animations.dart b/packages/flutter/lib/src/animation/animations.dart
index 6acc193..831948d 100644
--- a/packages/flutter/lib/src/animation/animations.dart
+++ b/packages/flutter/lib/src/animation/animations.dart
@@ -63,7 +63,7 @@
 /// Implements most of the [Animation] interface, by deferring its behavior to a
 /// given [parent] Animation. To implement an [Animation] that proxies to a
 /// parent, this class plus implementing "T get value" is all that is necessary.
-abstract class ProxyAnimatedMixin<T> {
+abstract class AnimationWithParentMixin<T> {
   /// The animation whose value this animation will proxy.
   ///
   /// This animation must remain the same for the lifetime of this object. If
@@ -87,7 +87,7 @@
 /// object, and then later change the animation from which the proxy receieves
 /// its value.
 class ProxyAnimation extends Animation<double>
-  with LazyListenerMixin, LocalListenersMixin, LocalAnimationStatusListenersMixin {
+  with AnimationLazyListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
   ProxyAnimation([Animation<double> animation]) {
     _parent = animation;
     if (_parent == null) {
@@ -158,7 +158,7 @@
 /// 0.0 because the tween does not change the status or direction of the
 /// animation.
 class ReverseAnimation extends Animation<double>
-  with LazyListenerMixin, LocalAnimationStatusListenersMixin {
+  with AnimationLazyListenerMixin, AnimationLocalStatusListenersMixin {
   ReverseAnimation(this.parent);
 
   /// The animation whose value and direction this animation is reversing.
@@ -211,7 +211,7 @@
 /// [CurvedAnimation] is useful when you wish to apply a [Curve] and you already
 /// have the underlying animation object. If you don't yet have an animation and
 /// want to apply a [Curve] to a [Tween], consider using [CurveTween].
-class CurvedAnimation extends Animation<double> with ProxyAnimatedMixin<double> {
+class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<double> {
   CurvedAnimation({
     this.parent,
     this.curve: Curves.linear,
@@ -283,7 +283,7 @@
 /// removed, it exposes a [dispose()] method. Call this method to shut this
 /// object down.
 class TrainHoppingAnimation extends Animation<double>
-  with EagerListenerMixin, LocalListenersMixin, LocalAnimationStatusListenersMixin {
+  with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
   TrainHoppingAnimation(this._currentTrain, this._nextTrain, { this.onSwitchedTrain }) {
     assert(_currentTrain != null);
     if (_nextTrain != null) {
diff --git a/packages/flutter/lib/src/animation/listener_helpers.dart b/packages/flutter/lib/src/animation/listener_helpers.dart
index 809a40c..fb761e5 100644
--- a/packages/flutter/lib/src/animation/listener_helpers.dart
+++ b/packages/flutter/lib/src/animation/listener_helpers.dart
@@ -12,7 +12,7 @@
 }
 
 /// A mixin that helps listen to another object only when this object has registered listeners.
-abstract class LazyListenerMixin implements _ListenerMixin {
+abstract class AnimationLazyListenerMixin implements _ListenerMixin {
   int _listenerCounter = 0;
   void didRegisterListener() {
     assert(_listenerCounter >= 0);
@@ -33,7 +33,7 @@
 
 /// A mixin that replaces the didRegisterListener/didUnregisterListener contract
 /// with a dispose contract.
-abstract class EagerListenerMixin implements _ListenerMixin {
+abstract class AnimationEagerListenerMixin implements _ListenerMixin {
   void didRegisterListener() { }
   void didUnregisterListener() { }
 
@@ -43,7 +43,7 @@
 
 /// A mixin that implements the addListener/removeListener protocol and notifies
 /// all the registered listeners when notifyListeners is invoked.
-abstract class LocalListenersMixin extends _ListenerMixin {
+abstract class AnimationLocalListenersMixin extends _ListenerMixin {
   final List<VoidCallback> _listeners = <VoidCallback>[];
   void addListener(VoidCallback listener) {
     didRegisterListener();
@@ -63,7 +63,7 @@
 /// A mixin that implements the addStatusListener/removeStatusListener protocol
 /// and notifies all the registered listeners when notifyStatusListeners is
 /// invoked.
-abstract class LocalAnimationStatusListenersMixin extends _ListenerMixin {
+abstract class AnimationLocalStatusListenersMixin extends _ListenerMixin {
   final List<AnimationStatusListener> _statusListeners = <AnimationStatusListener>[];
   void addStatusListener(AnimationStatusListener listener) {
     didRegisterListener();
diff --git a/packages/flutter/lib/src/animation/tween.dart b/packages/flutter/lib/src/animation/tween.dart
index 5acd1b4..3d002d7 100644
--- a/packages/flutter/lib/src/animation/tween.dart
+++ b/packages/flutter/lib/src/animation/tween.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' show Color, Size, Rect, VoidCallback, lerpDouble;
+import 'dart:ui' show Color, Size, Rect, VoidCallback;
 
 import 'animation.dart';
 import 'animations.dart';
@@ -28,7 +28,7 @@
   }
 }
 
-class _AnimatedEvaluation<T> extends Animation<T> with ProxyAnimatedMixin<double> {
+class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> {
   _AnimatedEvaluation(this.parent, this._evaluatable);
 
   /// The animation from which this value is derived.
diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart
index 0cc7c63..42c58bb 100644
--- a/packages/flutter/lib/src/gestures/binding.dart
+++ b/packages/flutter/lib/src/gestures/binding.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:typed_data';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show window;
 
 import 'package:flutter/services.dart';
 import 'package:mojo/bindings.dart' as mojo_bindings;
diff --git a/packages/flutter/lib/src/gestures/multidrag.dart b/packages/flutter/lib/src/gestures/multidrag.dart
new file mode 100644
index 0000000..2c11fbf
--- /dev/null
+++ b/packages/flutter/lib/src/gestures/multidrag.dart
@@ -0,0 +1,288 @@
+// 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:ui' show Point, Offset;
+
+import 'arena.dart';
+import 'constants.dart';
+import 'events.dart';
+import 'pointer_router.dart';
+import 'recognizer.dart';
+import 'velocity_tracker.dart';
+
+typedef Drag GestureMultiDragStartCallback(Point position);
+
+class Drag {
+  void move(Offset offset) { }
+  void end(Offset velocity) { }
+  void cancel() { }
+}
+
+abstract class MultiDragPointerState {
+  MultiDragPointerState(this.initialPosition);
+
+  final Point initialPosition;
+
+  final VelocityTracker _velocityTracker = new VelocityTracker();
+  Drag _client;
+
+  Offset get pendingDelta => _pendingDelta;
+  Offset _pendingDelta = Offset.zero;
+
+  GestureArenaEntry _arenaEntry;
+  void _setArenaEntry(GestureArenaEntry entry) {
+    assert(_arenaEntry == null);
+    assert(pendingDelta != null);
+    assert(_client == null);
+    _arenaEntry = entry;
+  }
+
+  void resolve(GestureDisposition disposition) {
+    _arenaEntry.resolve(disposition);
+  }
+
+  void _move(PointerMoveEvent event) {
+    assert(_arenaEntry != null);
+    _velocityTracker.addPosition(event.timeStamp, event.position);
+    if (_client != null) {
+      assert(pendingDelta == null);
+      _client.move(event.delta);
+    } else {
+      assert(pendingDelta != null);
+      _pendingDelta += event.delta;
+      checkForResolutionAfterMove();
+    }
+    return null;
+  }
+
+  /// Override this to call resolve() if the drag should be accepted or rejected.
+  /// This is called when a pointer movement is received, but only if the gesture
+  /// has not yet been resolved.
+  void checkForResolutionAfterMove() { }
+
+  /// Called when the gesture was accepted.
+  void accepted(Drag client) {
+    assert(_arenaEntry != null);
+    assert(_client == null);
+    _client = client;
+    _client.move(pendingDelta);
+    _pendingDelta = null;
+  }
+
+  /// Called when the gesture was rejected.
+  void rejected() {
+    assert(_arenaEntry != null);
+    assert(_client == null);
+    assert(pendingDelta != null);
+    _pendingDelta = null;
+    _arenaEntry = null;
+  }
+
+  void _up() {
+    assert(_arenaEntry != null);
+    if (_client != null) {
+      assert(pendingDelta == null);
+      _client.end(_velocityTracker.getVelocity());
+      _client = null;
+    } else {
+      assert(pendingDelta != null);
+      _pendingDelta = null;
+    }
+    _arenaEntry = null;
+  }
+
+  void _cancel() {
+    assert(_arenaEntry != null);
+    if (_client != null) {
+      assert(pendingDelta == null);
+      _client.cancel();
+      _client = null;
+    } else {
+      assert(pendingDelta != null);
+      _pendingDelta = null;
+    }
+    _arenaEntry = null;
+  }
+
+  void dispose() { }
+}
+
+abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> extends GestureRecognizer {
+
+  MultiDragGestureRecognizer({
+    PointerRouter pointerRouter,
+    GestureArena gestureArena,
+    this.onStart
+  }) : _pointerRouter = pointerRouter, _gestureArena = gestureArena {
+    assert(pointerRouter != null);
+    assert(gestureArena != null);
+  }
+
+  final PointerRouter _pointerRouter;
+  final GestureArena _gestureArena;
+  GestureMultiDragStartCallback onStart;
+
+  Map<int, T> _pointers = <int, T>{};
+
+  void addPointer(PointerDownEvent event) {
+    assert(_pointers != null);
+    assert(event.pointer != null);
+    assert(event.position != null);
+    assert(!_pointers.containsKey(event.pointer));
+    T state = createNewPointerState(event);
+    _pointers[event.pointer] = state;
+    _pointerRouter.addRoute(event.pointer, handleEvent);
+    state._setArenaEntry(_gestureArena.add(event.pointer, this));
+  }
+
+  T createNewPointerState(PointerDownEvent event);
+
+  void handleEvent(PointerEvent event) {
+    assert(_pointers != null);
+    assert(event.pointer != null);
+    assert(event.timeStamp != null);
+    assert(event.position != null);
+    assert(_pointers.containsKey(event.pointer));
+    T state = _pointers[event.pointer];
+    if (event is PointerMoveEvent) {
+      state._move(event);
+    } else if (event is PointerUpEvent) {
+      assert(event.delta == Offset.zero);
+      state._up();
+      _removeState(event.pointer);
+    } else if (event is PointerCancelEvent) {
+      assert(event.delta == Offset.zero);
+      state._cancel();
+      _removeState(event.pointer);
+    } else if (event is! PointerDownEvent) {
+      // we get the PointerDownEvent that resulted in our addPointer gettig called since we
+      // add ourselves to the pointer router then (before the pointer router has heard of
+      // the event).
+      assert(false);
+    }
+  }
+
+  void acceptGesture(int pointer) {
+    assert(_pointers != null);
+    T state = _pointers[pointer];
+    assert(state != null);
+    Drag drag;
+    if (onStart != null)
+      drag = onStart(state.initialPosition);
+    if (drag != null) {
+      state.accepted(drag);
+    } else {
+      _removeState(pointer);
+    }
+  }
+
+  void rejectGesture(int pointer) {
+    assert(_pointers != null);
+    if (_pointers.containsKey(pointer)) {
+      T state = _pointers[pointer];
+      assert(state != null);
+      state.rejected();
+      _removeState(pointer);
+    } // else we already preemptively forgot about it (e.g. we got an up event)
+  }
+
+  void _removeState(int pointer) {
+    assert(_pointers != null);
+    assert(_pointers.containsKey(pointer));
+    _pointerRouter.removeRoute(pointer, handleEvent);
+    _pointers[pointer].dispose();
+    _pointers.remove(pointer);
+  }
+
+  void dispose() {
+    for (int pointer in _pointers.keys)
+      _removeState(pointer);
+    _pointers = null;
+    super.dispose();
+  }
+
+}
+
+
+class _ImmediatePointerState extends MultiDragPointerState {
+  _ImmediatePointerState(Point initialPosition) : super(initialPosition);
+
+  void checkForResolutionAfterMove() {
+    assert(pendingDelta != null);
+    if (pendingDelta.distance > kTouchSlop)
+      resolve(GestureDisposition.accepted);
+  }
+}
+
+class ImmediateMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_ImmediatePointerState> {
+  ImmediateMultiDragGestureRecognizer({
+    PointerRouter pointerRouter,
+    GestureArena gestureArena,
+    GestureMultiDragStartCallback onStart
+  }) : super(pointerRouter: pointerRouter, gestureArena: gestureArena, onStart: onStart);
+
+  _ImmediatePointerState createNewPointerState(PointerDownEvent event) {
+    return new _ImmediatePointerState(event.position);
+  }
+}
+
+class _DelayedPointerState extends MultiDragPointerState {
+  _DelayedPointerState(Point initialPosition, Duration delay) : super(initialPosition) {
+    assert(delay != null);
+    _timer = new Timer(delay, _delayPassed);
+  }
+
+  Timer _timer;
+
+  void _delayPassed() {
+    assert(_timer != null);
+    assert(pendingDelta != null);
+    assert(pendingDelta.distance <= kTouchSlop);
+    resolve(GestureDisposition.accepted);
+    _timer = null;
+  }
+
+  void accepted(Drag client) {
+    _timer?.cancel();
+    _timer = null;
+    super.accepted(client);
+  }
+
+  void checkForResolutionAfterMove() {
+    assert(_timer != null);
+    assert(pendingDelta != null);
+    if (pendingDelta.distance > kTouchSlop)
+      resolve(GestureDisposition.rejected);
+  }
+
+  void dispose() {
+    _timer?.cancel();
+    _timer = null;
+    super.dispose();
+  }
+}
+
+class DelayedMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_DelayedPointerState> {
+  DelayedMultiDragGestureRecognizer({
+    PointerRouter pointerRouter,
+    GestureArena gestureArena,
+    GestureMultiDragStartCallback onStart,
+    Duration delay: kLongPressTimeout
+  }) : _delay = delay,
+       super(pointerRouter: pointerRouter, gestureArena: gestureArena, onStart: onStart) {
+    assert(delay != null);
+  }
+
+  Duration get delay => _delay;
+  Duration _delay;
+  void set delay(Duration value) {
+    assert(value != null);
+    _delay = value;
+  }
+
+  _DelayedPointerState createNewPointerState(PointerDownEvent event) {
+    return new _DelayedPointerState(event.position, _delay);
+  }
+}
diff --git a/packages/flutter/lib/src/gestures/multitap.dart b/packages/flutter/lib/src/gestures/multitap.dart
index 389fbe7..9f40fef 100644
--- a/packages/flutter/lib/src/gestures/multitap.dart
+++ b/packages/flutter/lib/src/gestures/multitap.dart
@@ -290,7 +290,7 @@
     if (_wonArena)
       reject();
     else
-      entry.resolve(GestureDisposition.rejected);
+      entry.resolve(GestureDisposition.rejected); // eventually calls reject()
   }
 
   void _check() {
diff --git a/packages/flutter/lib/src/gestures/recognizer.dart b/packages/flutter/lib/src/gestures/recognizer.dart
index c120ef2..6438da3 100644
--- a/packages/flutter/lib/src/gestures/recognizer.dart
+++ b/packages/flutter/lib/src/gestures/recognizer.dart
@@ -13,23 +13,45 @@
 
 export 'pointer_router.dart' show PointerRouter;
 
+/// The base class that all GestureRecognizers should inherit from.
+///
+/// Provides a basic API that can be used by classes that work with
+/// gesture recognizers but don't care about the specific details of
+/// the gestures recognizers themselves.
 abstract class GestureRecognizer extends GestureArenaMember {
 
-  /// Calls this with the pointerdown event of each pointer that should be
-  /// considered for this gesture.
+  /// Registers a new pointer that might be relevant to this gesture
+  /// detector.
   ///
-  /// It's the GestureRecognizer's responsibility to then add itself to the
-  /// global pointer router to receive subsequent events for this pointer.
+  /// The owner of this gesture recognizer calls addPointer() with the
+  /// PointerDownEvent of each pointer that should be considered for
+  /// this gesture.
+  ///
+  /// It's the GestureRecognizer's responsibility to then add itself
+  /// to the global pointer router (see [PointerRouter]) to receive
+  /// subsequent events for this pointer, and to add the pointer to
+  /// the global gesture arena manager (see [GestureArena]) to track
+  /// that pointer.
   void addPointer(PointerDownEvent event);
 
   /// Releases any resources used by the object.
   ///
-  /// This method is called when the object is no longer needed (e.g. a gesture
-  /// recogniser is being unregistered from a [GestureDetector]).
+  /// This method is called by the owner of this gesture recognizer
+  /// when the object is no longer needed (e.g. when a gesture
+  /// recogniser is being unregistered from a [GestureDetector], the
+  /// GestureDetector widget calls this method).
   void dispose() { }
 
 }
 
+/// Base class for gesture recognizers that can only recognize one
+/// gesture at a time. For example, a single [TapGestureRecognizer]
+/// can never recognize two taps happening simultaneously, even if
+/// multiple pointers are placed on the same widget.
+///
+/// This is in contrast to, for instance, [MultiTapGestureRecognizer],
+/// which manages each pointer independently and can consider multiple
+/// simultaneous touches to each result in a separate tap.
 abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
   OneSequenceGestureRecognizer({
     PointerRouter router,
diff --git a/packages/flutter/lib/src/gestures/velocity_tracker.dart b/packages/flutter/lib/src/gestures/velocity_tracker.dart
index 42d6d12..439041e 100644
--- a/packages/flutter/lib/src/gestures/velocity_tracker.dart
+++ b/packages/flutter/lib/src/gestures/velocity_tracker.dart
@@ -8,25 +8,27 @@
 
 export 'dart:ui' show Point, Offset;
 
-class _Estimator {
-  int degree;
-  Duration time;
-  List<double> xCoefficients;
-  List<double> yCoefficients;
-  double confidence;
+class _Estimate {
+  const _Estimate({ this.xCoefficients, this.yCoefficients, this.time, this.degree, this.confidence });
+
+  final List<double> xCoefficients;
+  final List<double> yCoefficients;
+  final Duration time;
+  final int degree;
+  final double confidence;
 
   String toString() {
-    return 'Estimator(degree: $degree, '
-                     'time: $time, '
-                     'confidence: $confidence, '
-                     'xCoefficients: $xCoefficients, '
-                     'yCoefficients: $yCoefficients)';
+    return 'Estimate(xCoefficients: $xCoefficients, '
+                    'yCoefficients: $yCoefficients, '
+                    'time: $time, '
+                    'degree: $degree, '
+                    'confidence: $confidence)';
   }
 }
 
 abstract class _VelocityTrackerStrategy {
   void addMovement(Duration timeStamp, Point position);
-  bool getEstimator(_Estimator estimator);
+  _Estimate getEstimate();
   void clear();
 }
 
@@ -80,7 +82,7 @@
     movement.position = position;
   }
 
-  bool getEstimator(_Estimator estimator) {
+  _Estimate getEstimate() {
     // Iterate over movement samples in reverse time order and collect samples.
     List<double> x = new List<double>();
     List<double> y = new List<double>();
@@ -107,7 +109,7 @@
     } while (m < kHistorySize);
 
     if (m == 0) // because we broke out of the loop above after age > kHorizonMilliseconds
-      return false; // no data
+      return null; // no data
 
     // Calculate a least squares polynomial fit.
     int n = degree;
@@ -121,24 +123,26 @@
         LeastSquaresSolver ySolver = new LeastSquaresSolver(time, y, w);
         PolynomialFit yFit = ySolver.solve(n);
         if (yFit != null) {
-          estimator.xCoefficients = xFit.coefficients;
-          estimator.yCoefficients = yFit.coefficients;
-          estimator.time = newestMovement.eventTime;
-          estimator.degree = n;
-          estimator.confidence = xFit.confidence * yFit.confidence;
-          return true;
+          return new _Estimate(
+            xCoefficients: xFit.coefficients,
+            yCoefficients: yFit.coefficients,
+            time: newestMovement.eventTime,
+            degree: n,
+            confidence: xFit.confidence * yFit.confidence
+          );
         }
       }
     }
 
     // No velocity data available for this pointer, but we do have its current
     // position.
-    estimator.xCoefficients = <double>[ x[0] ];
-    estimator.yCoefficients = <double>[ y[0] ];
-    estimator.time = newestMovement.eventTime;
-    estimator.degree = 0;
-    estimator.confidence = 1.0;
-    return true;
+    return new _Estimate(
+      xCoefficients: <double>[ x[0] ],
+      yCoefficients: <double>[ y[0] ],
+      time: newestMovement.eventTime,
+      degree: 0,
+      confidence: 1.0
+    );
   }
 
   void clear() {
@@ -204,27 +208,52 @@
 
 }
 
+/// Computes a pointer velocity based on data from PointerMove events.
+///
+/// The input data is provided by calling addPosition(). Adding data
+/// is cheap.
+///
+/// To obtain a velocity, call getVelocity(). This will compute the
+/// velocity based on the data added so far. Only call this when you
+/// need to use the velocity, as it is comparatively expensive.
+///
+/// The quality of the velocity estimation will be better if more data
+/// points have been received.
 class VelocityTracker {
-  static const int kAssumePointerMoveStoppedTimeMs = 40;
+
+  /// The maximum length of time between two move events to allow
+  /// before assuming the pointer stopped.
+  static const Duration kAssumePointerMoveStoppedTime = const Duration(milliseconds: 40);
 
   VelocityTracker() : _strategy = _createStrategy();
 
   Duration _lastTimeStamp = const Duration();
   _VelocityTrackerStrategy _strategy;
 
+  /// Add a given position corresponding to a specific time.
+  ///
+  /// If [kAssumePointerMoveStoppedTime] has elapsed since the last
+  /// call, then earlier data will be discarded.
   void addPosition(Duration timeStamp, Point position) {
-    if ((timeStamp - _lastTimeStamp).inMilliseconds >= kAssumePointerMoveStoppedTimeMs)
+    if (timeStamp - _lastTimeStamp >= kAssumePointerMoveStoppedTime)
       _strategy.clear();
     _lastTimeStamp = timeStamp;
     _strategy.addMovement(timeStamp, position);
   }
 
+  /// Computes the velocity of the pointer at the time of the last
+  /// provided data point.
+  ///
+  /// This can be expensive. Only call this when you need the velocity.
+  ///
+  /// getVelocity() will return null if no estimate is available or if
+  /// the velocity is zero.
   Offset getVelocity() {
-    _Estimator estimator = new _Estimator();
-    if (_strategy.getEstimator(estimator) && estimator.degree >= 1) {
+    _Estimate estimate = _strategy.getEstimate();
+    if (estimate != null && estimate.degree >= 1) {
       return new Offset( // convert from pixels/ms to pixels/s
-        estimator.xCoefficients[1] * 1000,
-        estimator.yCoefficients[1] * 1000
+        estimate.xCoefficients[1] * 1000,
+        estimate.yCoefficients[1] * 1000
       );
     }
     return null;
diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart
index 2d4f0a0..398e33f 100644
--- a/packages/flutter/lib/src/material/bottom_sheet.dart
+++ b/packages/flutter/lib/src/material/bottom_sheet.dart
@@ -4,9 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
 import 'colors.dart';
diff --git a/packages/flutter/lib/src/material/checkbox.dart b/packages/flutter/lib/src/material/checkbox.dart
index 6b2ba1b..b1fc424 100644
--- a/packages/flutter/lib/src/material/checkbox.dart
+++ b/packages/flutter/lib/src/material/checkbox.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Gradient;
 
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
@@ -122,23 +122,24 @@
     // Create an inner rectangle to cover inside of rectangle. This is needed to avoid
     // painting artefacts caused by overlayed paintings.
     Rect innerRect = rect.deflate(1.0);
-    ui.RRect rrect = new ui.RRect.fromRectXY(
-        rect, _kEdgeRadius, _kEdgeRadius);
+    RRect rrect = new RRect.fromRectXY(rect, _kEdgeRadius, _kEdgeRadius);
 
     // Outline of the empty rrect
-    paint.style = ui.PaintingStyle.stroke;
+    paint.style = PaintingStyle.stroke;
     canvas.drawRRect(rrect, paint);
 
     // Radial gradient that changes size
     if (!position.isDismissed) {
       paint
-        ..style = ui.PaintingStyle.fill
+        ..style = PaintingStyle.fill
         ..shader = new ui.Gradient.radial(
           new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
-          _kEdgeSize * (_kMidpoint - position.value) * 8.0, <Color>[
-        const Color(0x00000000),
-        inactiveColor
-      ]);
+          _kEdgeSize * (_kMidpoint - position.value) * 8.0,
+          <Color>[
+            const Color(0x00000000),
+            inactiveColor
+          ]
+        );
       canvas.drawRect(innerRect, paint);
     }
 
@@ -149,24 +150,22 @@
         // First draw a rounded rect outline then fill inner rectangle with the active color
         paint
           ..color = activeColor.withAlpha((t * 255).floor())
-          ..style = ui.PaintingStyle.stroke;
+          ..style = PaintingStyle.stroke;
         canvas.drawRRect(rrect, paint);
-        paint.style = ui.PaintingStyle.fill;
+        paint.style = PaintingStyle.fill;
         canvas.drawRect(innerRect, paint);
       }
 
       // White inner check
       paint
         ..color = const Color(0xFFFFFFFF)
-        ..style = ui.PaintingStyle.stroke;
+        ..style = PaintingStyle.stroke;
       Path path = new Path();
       Point start = new Point(_kEdgeSize * 0.15, _kEdgeSize * 0.45);
       Point mid = new Point(_kEdgeSize * 0.4, _kEdgeSize * 0.7);
       Point end = new Point(_kEdgeSize * 0.85, _kEdgeSize * 0.25);
-      Point lerp(Point p1, Point p2, double t) =>
-          new Point(p1.x * (1.0 - t) + p2.x * t, p1.y * (1.0 - t) + p2.y * t);
-      Point drawStart = lerp(start, mid, 1.0 - t);
-      Point drawEnd = lerp(mid, end, t);
+      Point drawStart = Point.lerp(start, mid, 1.0 - t);
+      Point drawEnd = Point.lerp(mid, end, t);
       path.moveTo(offsetX + drawStart.x, offsetY + drawStart.y);
       path.lineTo(offsetX + mid.x, offsetY + mid.y);
       path.lineTo(offsetX + drawEnd.x, offsetY + drawEnd.y);
diff --git a/packages/flutter/lib/src/material/circle_avatar.dart b/packages/flutter/lib/src/material/circle_avatar.dart
index dcd8c83..39e51be 100644
--- a/packages/flutter/lib/src/material/circle_avatar.dart
+++ b/packages/flutter/lib/src/material/circle_avatar.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/painting.dart';
 import 'package:flutter/widgets.dart';
 
 import 'constants.dart';
diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart
index 18bdfb6..dae65a5 100644
--- a/packages/flutter/lib/src/material/dialog.dart
+++ b/packages/flutter/lib/src/material/dialog.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'colors.dart';
diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart
index a87773b..d3f2480 100644
--- a/packages/flutter/lib/src/material/drawer.dart
+++ b/packages/flutter/lib/src/material/drawer.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'colors.dart';
diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart
index 2596368..db0c8ac 100644
--- a/packages/flutter/lib/src/material/dropdown.dart
+++ b/packages/flutter/lib/src/material/dropdown.dart
@@ -4,9 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
 import 'debug.dart';
diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart
index 85cdecc..679cecf 100644
--- a/packages/flutter/lib/src/material/flexible_space_bar.dart
+++ b/packages/flutter/lib/src/material/flexible_space_bar.dart
@@ -4,7 +4,6 @@
 
 import 'dart:math' as math;
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'debug.dart';
diff --git a/packages/flutter/lib/src/material/floating_action_button.dart b/packages/flutter/lib/src/material/floating_action_button.dart
index 5519d73..da1454c 100644
--- a/packages/flutter/lib/src/material/floating_action_button.dart
+++ b/packages/flutter/lib/src/material/floating_action_button.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'icon_theme.dart';
diff --git a/packages/flutter/lib/src/material/icon_theme_data.dart b/packages/flutter/lib/src/material/icon_theme_data.dart
index 46dffa1..dc4b42d 100644
--- a/packages/flutter/lib/src/material/icon_theme_data.dart
+++ b/packages/flutter/lib/src/material/icon_theme_data.dart
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show lerpDouble;
+import 'dart:ui' show hashValues;
 
 enum IconThemeColor { white, black }
 
@@ -28,7 +29,7 @@
     return color == typedOther.color && opacity == typedOther.opacity;
   }
 
-  int get hashCode => ui.hashValues(color, opacity);
+  int get hashCode => hashValues(color, opacity);
 
   String toString() => '$color';
 }
diff --git a/packages/flutter/lib/src/material/input.dart b/packages/flutter/lib/src/material/input.dart
index 1597ef4..9dada4e 100644
--- a/packages/flutter/lib/src/material/input.dart
+++ b/packages/flutter/lib/src/material/input.dart
@@ -2,26 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
-import 'package:sky_services/editing/editing.mojom.dart' as mojom;
 
 import 'colors.dart';
 import 'debug.dart';
 import 'icon.dart';
 import 'theme.dart';
 
-export 'package:flutter/rendering.dart' show ValueChanged;
 export 'package:sky_services/editing/editing.mojom.dart' show KeyboardType;
 
 /// A material design text input field.
 class Input extends StatefulComponent {
   Input({
     GlobalKey key,
-    this.initialValue: '',
-    this.initialSelection,
+    this.value: InputValue.empty,
     this.keyboardType: KeyboardType.text,
     this.icon,
     this.labelText,
@@ -37,11 +32,8 @@
     assert(key != null);
   }
 
-  /// The initial editable text for the input field.
-  final String initialValue;
-
-  /// The initial selection for this input field.
-  final TextSelection initialSelection;
+  /// The text of the input field.
+  final InputValue value;
 
   /// The type of keyboard to use for editing the text.
   final KeyboardType keyboardType;
@@ -71,10 +63,10 @@
   final bool autofocus;
 
   /// Called when the text being edited changes.
-  final ValueChanged<String> onChanged;
+  final ValueChanged<InputValue> onChanged;
 
   /// Called when the user indicates that they are done editing the text in the field.
-  final ValueChanged<String> onSubmitted;
+  final ValueChanged<InputValue> onSubmitted;
 
   _InputState createState() => new _InputState();
 }
@@ -83,89 +75,13 @@
 const Curve _kTransitionCurve = Curves.ease;
 
 class _InputState extends State<Input> {
-  String _value;
-  EditableString _editableString;
-  KeyboardHandle _keyboardHandle;
-
-  // Used by tests.
-  EditableString get editableValue => _editableString;
-
-  void initState() {
-    super.initState();
-    _value = config.initialValue;
-    _editableString = new EditableString(
-      text: _value,
-      selection: config.initialSelection,
-      onUpdated: _handleTextUpdated,
-      onSubmitted: _handleTextSubmitted
-    );
-  }
-
-  void dispose() {
-    if (_isAttachedToKeyboard)
-      _keyboardHandle.release();
-    super.dispose();
-  }
-
-  bool get _isAttachedToKeyboard => _keyboardHandle != null && _keyboardHandle.attached;
-
-  void _attachOrDetachKeyboard(bool focused) {
-    if (focused && !_isAttachedToKeyboard) {
-      _keyboardHandle = keyboard.attach(_editableString.createStub(),
-                                        new mojom.KeyboardConfiguration()
-                                          ..type = config.keyboardType);
-      _keyboardHandle.setEditingState(_editableString.editingState);
-      _keyboardHandle.show();
-    } else if (!focused && _isAttachedToKeyboard) {
-      _keyboardHandle.release();
-      _keyboardHandle = null;
-      _editableString.didDetachKeyboard();
-    }
-  }
-
-  void _requestKeyboard() {
-    if (Focus.at(context)) {
-      assert(_isAttachedToKeyboard);
-      _keyboardHandle.show();
-    } else {
-      Focus.moveTo(config.key);
-      // we'll get told to rebuild and we'll take care of the keyboard then
-    }
-  }
-
-  void _handleTextUpdated() {
-    if (_value != _editableString.text) {
-      setState(() {
-        _value = _editableString.text;
-      });
-      if (config.onChanged != null)
-        config.onChanged(_value);
-    }
-  }
-
-  void _handleTextSubmitted() {
-    Focus.clear(context);
-    if (config.onSubmitted != null)
-      config.onSubmitted(_value);
-  }
-
-  void _handleSelectionChanged(TextSelection selection) {
-    if (_isAttachedToKeyboard) {
-      _editableString.setSelection(selection);
-      _keyboardHandle.setEditingState(_editableString.editingState);
-    } else {
-      _editableString.setSelection(selection);
-      _requestKeyboard();
-    }
-  }
+  GlobalKey<RawInputLineState> _rawInputLineKey = new GlobalKey<RawInputLineState>();
 
   Widget build(BuildContext context) {
     assert(debugCheckHasMaterial(context));
     ThemeData themeData = Theme.of(context);
     bool focused = Focus.at(context, autofocus: config.autofocus);
 
-    _attachOrDetachKeyboard(focused);
-
     TextStyle textStyle = config.style ?? themeData.text.subhead;
     Color focusHighlightColor = themeData.accentColor;
     if (themeData.primarySwatch != null)
@@ -174,7 +90,7 @@
 
     List<Widget> stackChildren = <Widget>[];
 
-    bool hasInlineLabel = config.labelText != null && !focused && !_value.isNotEmpty;
+    bool hasInlineLabel = config.labelText != null && !focused && !config.value.text.isNotEmpty;
 
     if (config.labelText != null) {
       TextStyle labelStyle = hasInlineLabel ?
@@ -197,7 +113,7 @@
       topPadding += topPaddingIncrement;
     }
 
-    if (config.hintText != null && _value.isEmpty && !hasInlineLabel) {
+    if (config.hintText != null && config.value.text.isEmpty && !hasInlineLabel) {
       TextStyle hintStyle = themeData.text.subhead.copyWith(color: themeData.hintColor);
       stackChildren.add(new Positioned(
         left: 0.0,
@@ -237,14 +153,17 @@
           )
         )
       ),
-      child: new RawEditableLine(
-        value: _editableString,
-        focused: focused,
+      child: new RawInputLine(
+        key: _rawInputLineKey,
+        value: config.value,
+        focusKey: config.key,
         style: textStyle,
         hideText: config.hideText,
         cursorColor: cursorColor,
         selectionColor: cursorColor,
-        onSelectionChanged: _handleSelectionChanged
+        keyboardType: config.keyboardType,
+        onChanged: config.onChanged,
+        onSubmitted: config.onSubmitted
       )
     ));
 
@@ -281,7 +200,7 @@
 
     return new GestureDetector(
       behavior: HitTestBehavior.opaque,
-      onTap: _requestKeyboard,
+      onTap: () => _rawInputLineKey.currentState?.requestKeyboard(),
       child: new Padding(
         padding: const EdgeDims.symmetric(horizontal: 16.0),
         child: child
diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart
index eb7de2c..2915b6c 100644
--- a/packages/flutter/lib/src/material/material.dart
+++ b/packages/flutter/lib/src/material/material.dart
@@ -4,8 +4,6 @@
 
 import 'dart:math' as math;
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/painting.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 import 'package:vector_math/vector_math_64.dart';
diff --git a/packages/flutter/lib/src/material/material_app.dart b/packages/flutter/lib/src/material/material_app.dart
index c674755..d69430f 100644
--- a/packages/flutter/lib/src/material/material_app.dart
+++ b/packages/flutter/lib/src/material/material_app.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show WindowPadding, window;
 
 import 'package:flutter/rendering.dart';
 import 'package:flutter/services.dart';
@@ -12,6 +12,8 @@
 import 'page.dart';
 import 'theme.dart';
 
+export 'dart:ui' show Locale;
+
 const TextStyle _errorTextStyle = const TextStyle(
   color: const Color(0xD0FF0000),
   fontFamily: 'monospace',
@@ -38,7 +40,7 @@
 }
 typedef Widget RouteBuilder(RouteArguments args);
 
-typedef Future<LocaleQueryData> LocaleChangedCallback(ui.Locale locale);
+typedef Future<LocaleQueryData> LocaleChangedCallback(Locale locale);
 
 class MaterialApp extends StatefulComponent {
   MaterialApp({
@@ -152,7 +154,7 @@
     });
   }
 
-  void didChangeLocale(ui.Locale locale) {
+  void didChangeLocale(Locale locale) {
     if (config.onLocaleChanged != null) {
       config.onLocaleChanged(locale).then((LocaleQueryData data) {
         if (mounted)
@@ -161,7 +163,7 @@
     }
   }
 
-  void didChangeAppLifecycleState(ui.AppLifecycleState state) { }
+  void didChangeAppLifecycleState(AppLifecycleState state) { }
 
   final HeroController _heroController = new HeroController();
 
diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart
index 2ad1658..1401a3c 100644
--- a/packages/flutter/lib/src/material/page.dart
+++ b/packages/flutter/lib/src/material/page.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 class _MaterialPageTransition extends AnimatedComponent {
diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart
index ddf1610..2fa5473 100644
--- a/packages/flutter/lib/src/material/popup_menu.dart
+++ b/packages/flutter/lib/src/material/popup_menu.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'ink_well.dart';
diff --git a/packages/flutter/lib/src/material/progress_indicator.dart b/packages/flutter/lib/src/material/progress_indicator.dart
index c58a923..e7e5017 100644
--- a/packages/flutter/lib/src/material/progress_indicator.dart
+++ b/packages/flutter/lib/src/material/progress_indicator.dart
@@ -3,9 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'theme.dart';
@@ -86,7 +84,7 @@
   void paint(Canvas canvas, Size size) {
     Paint paint = new Paint()
       ..color = backgroundColor
-      ..style = ui.PaintingStyle.fill;
+      ..style = PaintingStyle.fill;
     canvas.drawRect(Point.origin & size, paint);
 
     paint.color = valueColor;
@@ -155,7 +153,7 @@
     Paint paint = new Paint()
       ..color = valueColor
       ..strokeWidth = _kCircularProgressIndicatorStrokeWidth
-      ..style = ui.PaintingStyle.stroke;
+      ..style = PaintingStyle.stroke;
 
     if (value != null) {
       double angle = value.clamp(0.0, 1.0) * _kSweep;
diff --git a/packages/flutter/lib/src/material/radio.dart b/packages/flutter/lib/src/material/radio.dart
index 555b0e7..c90b302 100644
--- a/packages/flutter/lib/src/material/radio.dart
+++ b/packages/flutter/lib/src/material/radio.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
@@ -116,13 +114,13 @@
     // Outer circle
     Paint paint = new Paint()
       ..color = Color.lerp(inactiveColor, radioColor, position.value)
-      ..style = ui.PaintingStyle.stroke
+      ..style = PaintingStyle.stroke
       ..strokeWidth = 2.0;
     canvas.drawCircle(center, _kOuterRadius, paint);
 
     // Inner circle
     if (!position.isDismissed) {
-      paint.style = ui.PaintingStyle.fill;
+      paint.style = PaintingStyle.fill;
       canvas.drawCircle(center, _kInnerRadius * position.value, paint);
     }
   }
diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart
index 40bb8e3..74d36f7 100644
--- a/packages/flutter/lib/src/material/scaffold.dart
+++ b/packages/flutter/lib/src/material/scaffold.dart
@@ -6,8 +6,6 @@
 import 'dart:collection';
 import 'dart:math' as math;
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
 import 'bottom_sheet.dart';
diff --git a/packages/flutter/lib/src/material/scrollbar_painter.dart b/packages/flutter/lib/src/material/scrollbar_painter.dart
index 6a461db..4eb4858 100644
--- a/packages/flutter/lib/src/material/scrollbar_painter.dart
+++ b/packages/flutter/lib/src/material/scrollbar_painter.dart
@@ -4,8 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
 const double _kMinScrollbarThumbLength = 18.0;
diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart
index 2d4cc6c..e5011d5 100644
--- a/packages/flutter/lib/src/material/slider.dart
+++ b/packages/flutter/lib/src/material/slider.dart
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/gestures.dart';
-import 'package:flutter/painting.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart
index 410bcfe..59cc63f 100644
--- a/packages/flutter/lib/src/material/snack_bar.dart
+++ b/packages/flutter/lib/src/material/snack_bar.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'flat_button.dart';
diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart
index e7bfcfe..38f33be 100644
--- a/packages/flutter/lib/src/material/switch.dart
+++ b/packages/flutter/lib/src/material/switch.dart
@@ -2,10 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
 import 'package:flutter/gestures.dart';
-import 'package:flutter/painting.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
@@ -194,13 +191,13 @@
       size.width - 2.0 * trackHorizontalPadding,
       _kTrackHeight
     );
-    ui.RRect trackRRect = new ui.RRect.fromRectXY(
-        trackRect, _kTrackRadius, _kTrackRadius);
+    RRect trackRRect = new RRect.fromRectXY(trackRect, _kTrackRadius, _kTrackRadius);
     canvas.drawRRect(trackRRect, paint);
 
     Offset thumbOffset = new Offset(
       offset.dx + kRadialReactionRadius + position.value * _trackInnerLength,
-      offset.dy + size.height / 2.0);
+      offset.dy + size.height / 2.0
+    );
 
     paintRadialReaction(canvas, thumbOffset);
 
diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart
index c466ea1..7faf817 100644
--- a/packages/flutter/lib/src/material/tabs.dart
+++ b/packages/flutter/lib/src/material/tabs.dart
@@ -6,7 +6,6 @@
 import 'dart:math' as math;
 
 import 'package:newton/newton.dart';
-import 'package:flutter/animation.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
diff --git a/packages/flutter/lib/src/material/theme.dart b/packages/flutter/lib/src/material/theme.dart
index 50bea89..d6458e3 100644
--- a/packages/flutter/lib/src/material/theme.dart
+++ b/packages/flutter/lib/src/material/theme.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'theme_data.dart';
diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart
index 195310e..94bd578 100644
--- a/packages/flutter/lib/src/material/time_picker.dart
+++ b/packages/flutter/lib/src/material/time_picker.dart
@@ -4,10 +4,7 @@
 
 import 'dart:math' as math;
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
-import 'package:flutter/services.dart';
+import 'package:flutter/services.dart' show HapticFeedbackType, userFeedback;
 import 'package:flutter/widgets.dart';
 
 import 'colors.dart';
diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart
index 3bec742..35757bc 100644
--- a/packages/flutter/lib/src/material/tooltip.dart
+++ b/packages/flutter/lib/src/material/tooltip.dart
@@ -5,9 +5,6 @@
 import 'dart:async';
 import 'dart:math' as math;
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
 import 'colors.dart';
diff --git a/packages/flutter/lib/src/material/two_level_list.dart b/packages/flutter/lib/src/material/two_level_list.dart
index dae089a..0746b44 100644
--- a/packages/flutter/lib/src/material/two_level_list.dart
+++ b/packages/flutter/lib/src/material/two_level_list.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
 import 'package:flutter/widgets.dart';
 
 import 'colors.dart';
diff --git a/packages/flutter/lib/src/painting/basic_types.dart b/packages/flutter/lib/src/painting/basic_types.dart
index 2c40e5c..5cdf333 100644
--- a/packages/flutter/lib/src/painting/basic_types.dart
+++ b/packages/flutter/lib/src/painting/basic_types.dart
@@ -3,21 +3,51 @@
 // found in the LICENSE file.
 
 export 'dart:ui' show
+  BlurStyle,
   Canvas,
   Color,
   ColorFilter,
+  FilterQuality,
   FontStyle,
   FontWeight,
+  ImageShader,
+  LayerDrawLooperBuilder,
+  MaskFilter,
   Offset,
   Paint,
+  PaintingStyle,
   Path,
   Point,
+  RRect,
+  RSTransform,
   Rect,
+  Shader,
   Size,
+  StrokeCap,
   TextAlign,
   TextBaseline,
   TextDecoration,
   TextDecorationStyle,
+  TextDirection,
+  TileMode,
+  TransferMode,
+  VertexMode,
   VoidCallback,
   hashValues,
   hashList;
+
+// Intentionally not exported:
+//  - Image, decodeImageFromDataPipe, decodeImageFromList:
+//      We use ui.* to make it very explicit that these are low-level image APIs.
+//      Generally, higher layers provide more reasonable APIs around images.
+//  - lerpDouble:
+//      Hopefully this will eventually become Double.lerp.
+//  - Paragraph, ParagraphBuilder, ParagraphStyle, TextBox:
+//      These are low-level text primitives. Use this package's TextPainter API.
+//  - Picture, PictureRecorder, Scene, SceneBuilder:
+//      These are low-level primitives. Generally, the rendering layer makes these moot.
+//  - Gradient:
+//      Use this package's higher-level Gradient API instead.
+//  - window, WindowPadding
+//      These are generally wrapped by other APIs so we always refer to them directly
+//      as ui.* to avoid making them seem like high-level APIs.
diff --git a/packages/flutter/lib/src/painting/box_painter.dart b/packages/flutter/lib/src/painting/box_painter.dart
index 47db226..9f5cf28 100644
--- a/packages/flutter/lib/src/painting/box_painter.dart
+++ b/packages/flutter/lib/src/painting/box_painter.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image, Gradient, lerpDouble;
 
 import 'package:flutter/services.dart';
 
@@ -238,7 +238,7 @@
 /// A 2D gradient.
 abstract class Gradient {
   const Gradient();
-  ui.Shader createShader();
+  Shader createShader();
 }
 
 /// A 2D linear gradient.
@@ -248,7 +248,7 @@
     this.end,
     this.colors,
     this.stops,
-    this.tileMode: ui.TileMode.clamp
+    this.tileMode: TileMode.clamp
   });
 
   /// The point at which stop 0.0 of the gradient is placed.
@@ -269,9 +269,9 @@
   final List<double> stops;
 
   /// How this gradient should tile the plane.
-  final ui.TileMode tileMode;
+  final TileMode tileMode;
 
-  ui.Shader createShader() {
+  Shader createShader() {
     return new ui.Gradient.linear(<Point>[begin, end], this.colors, this.stops, this.tileMode);
   }
 
@@ -320,7 +320,7 @@
     this.radius,
     this.colors,
     this.stops,
-    this.tileMode: ui.TileMode.clamp
+    this.tileMode: TileMode.clamp
   });
 
   /// The center of the gradient.
@@ -343,9 +343,9 @@
   final List<double> stops;
 
   /// How this gradient should tile the plane.
-  final ui.TileMode tileMode;
+  final TileMode tileMode;
 
-  ui.Shader createShader() {
+  Shader createShader() {
     return new ui.Gradient.radial(center, radius, colors, stops, tileMode);
   }
 
@@ -869,7 +869,7 @@
     double shortestSide = rect.shortestSide;
     // In principle, we should use shortestSide / 2.0, but we don't want to
     // run into floating point rounding errors. Instead, we just use
-    // shortestSide and let ui.Canvas do any remaining clamping.
+    // shortestSide and let Canvas do any remaining clamping.
     return borderRadius > shortestSide ? shortestSide : borderRadius;
   }
 
@@ -879,7 +879,7 @@
     switch (shape) {
       case BoxShape.rectangle:
         if (borderRadius != null) {
-          ui.RRect bounds = new ui.RRect.fromRectXY(Point.origin & size, borderRadius, borderRadius);
+          RRect bounds = new RRect.fromRectXY(Point.origin & size, borderRadius, borderRadius);
           return bounds.contains(position);
         }
         return true;
@@ -938,7 +938,7 @@
     return hasUniformWidth;
   }
 
-  void _paintBox(ui.Canvas canvas, Rect rect, Paint paint) {
+  void _paintBox(Canvas canvas, Rect rect, Paint paint) {
     switch (_decoration.shape) {
       case BoxShape.circle:
         assert(_decoration.borderRadius == null);
@@ -951,30 +951,30 @@
           canvas.drawRect(rect, paint);
         } else {
           double radius = _decoration.getEffectiveBorderRadius(rect);
-          canvas.drawRRect(new ui.RRect.fromRectXY(rect, radius, radius), paint);
+          canvas.drawRRect(new RRect.fromRectXY(rect, radius, radius), paint);
         }
         break;
     }
   }
 
-  void _paintShadows(ui.Canvas canvas, Rect rect) {
+  void _paintShadows(Canvas canvas, Rect rect) {
     if (_decoration.boxShadow == null)
       return;
     for (BoxShadow boxShadow in _decoration.boxShadow) {
       final Paint paint = new Paint()
         ..color = boxShadow.color
-        ..maskFilter = new ui.MaskFilter.blur(ui.BlurStyle.normal, boxShadow._blurSigma);
+        ..maskFilter = new MaskFilter.blur(BlurStyle.normal, boxShadow._blurSigma);
       final Rect bounds = rect.shift(boxShadow.offset).inflate(boxShadow.spreadRadius);
       _paintBox(canvas, bounds, paint);
     }
   }
 
-  void _paintBackgroundColor(ui.Canvas canvas, Rect rect) {
+  void _paintBackgroundColor(Canvas canvas, Rect rect) {
     if (_decoration.backgroundColor != null || _decoration.gradient != null)
       _paintBox(canvas, rect, _backgroundPaint);
   }
 
-  void _paintBackgroundImage(ui.Canvas canvas, Rect rect) {
+  void _paintBackgroundImage(Canvas canvas, Rect rect) {
     final BackgroundImage backgroundImage = _decoration.backgroundImage;
     if (backgroundImage == null)
       return;
@@ -993,7 +993,7 @@
     );
   }
 
-  void _paintBorder(ui.Canvas canvas, Rect rect) {
+  void _paintBorder(Canvas canvas, Rect rect) {
     if (_decoration.border == null)
       return;
 
@@ -1056,19 +1056,19 @@
     canvas.drawPath(path, paint);
   }
 
-  void _paintBorderWithRadius(ui.Canvas canvas, Rect rect) {
+  void _paintBorderWithRadius(Canvas canvas, Rect rect) {
     assert(_hasUniformBorder);
     assert(_decoration.shape == BoxShape.rectangle);
     Color color = _decoration.border.top.color;
     double width = _decoration.border.top.width;
     double radius = _decoration.getEffectiveBorderRadius(rect);
 
-    ui.RRect outer = new ui.RRect.fromRectXY(rect, radius, radius);
-    ui.RRect inner = new ui.RRect.fromRectXY(rect.deflate(width), radius - width, radius - width);
+    RRect outer = new RRect.fromRectXY(rect, radius, radius);
+    RRect inner = new RRect.fromRectXY(rect.deflate(width), radius - width, radius - width);
     canvas.drawDRRect(outer, inner, new Paint()..color = color);
   }
 
-  void _paintBorderWithCircle(ui.Canvas canvas, Rect rect) {
+  void _paintBorderWithCircle(Canvas canvas, Rect rect) {
     assert(_hasUniformBorder);
     assert(_decoration.shape == BoxShape.circle);
     assert(_decoration.borderRadius == null);
@@ -1078,14 +1078,14 @@
     Paint paint = new Paint()
       ..color = _decoration.border.top.color
       ..strokeWidth = width
-      ..style = ui.PaintingStyle.stroke;
+      ..style = PaintingStyle.stroke;
     Point center = rect.center;
     double radius = (rect.shortestSide - width) / 2.0;
     canvas.drawCircle(center, radius, paint);
   }
 
   /// Paint the box decoration into the given location on the given canvas
-  void paint(ui.Canvas canvas, Rect rect) {
+  void paint(Canvas canvas, Rect rect) {
     _paintShadows(canvas, rect);
     _paintBackgroundColor(canvas, rect);
     _paintBackgroundImage(canvas, rect);
diff --git a/packages/flutter/lib/src/painting/decoration.dart b/packages/flutter/lib/src/painting/decoration.dart
index 2827d08..e0e0519 100644
--- a/packages/flutter/lib/src/painting/decoration.dart
+++ b/packages/flutter/lib/src/painting/decoration.dart
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
+import 'basic_types.dart';
 import 'edge_dims.dart';
 
 export 'edge_dims.dart' show EdgeDims;
@@ -16,14 +15,14 @@
   EdgeDims get padding => null;
   Decoration lerpFrom(Decoration a, double t) => this;
   Decoration lerpTo(Decoration b, double t) => b;
-  bool hitTest(ui.Size size, ui.Point position) => true;
+  bool hitTest(Size size, Point position) => true;
   bool get needsListeners => false;
-  void addChangeListener(ui.VoidCallback listener) { assert(false); }
-  void removeChangeListener(ui.VoidCallback listener) { assert(false); }
+  void addChangeListener(VoidCallback listener) { assert(false); }
+  void removeChangeListener(VoidCallback listener) { assert(false); }
   BoxPainter createBoxPainter();
   String toString([String prefix = '']) => '$prefix$runtimeType';
 }
 
 abstract class BoxPainter {
-  void paint(ui.Canvas canvas, ui.Rect rect);
+  void paint(Canvas canvas, Rect rect);
 }
diff --git a/packages/flutter/lib/src/painting/edge_dims.dart b/packages/flutter/lib/src/painting/edge_dims.dart
index 5a0990f..5fd4457 100644
--- a/packages/flutter/lib/src/painting/edge_dims.dart
+++ b/packages/flutter/lib/src/painting/edge_dims.dart
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-import 'dart:ui' show hashValues;
+import 'dart:ui' as ui show lerpDouble;
+
+import 'basic_types.dart';
 
 /// An immutable set of offsets in each of the four cardinal directions.
 ///
@@ -50,13 +51,13 @@
   double get vertical => top + bottom;
 
   /// The size that this EdgeDims would occupy with an empty interior.
-  ui.Size get collapsedSize => new ui.Size(horizontal, vertical);
+  Size get collapsedSize => new Size(horizontal, vertical);
 
   /// An EdgeDims with top and bottom as well as left and right flipped.
   EdgeDims get flipped => new EdgeDims.TRBL(bottom, left, top, right);
 
-  ui.Rect inflateRect(ui.Rect rect) {
-    return new ui.Rect.fromLTRB(rect.left - left, rect.top - top, rect.right + right, rect.bottom + bottom);
+  Rect inflateRect(Rect rect) {
+    return new Rect.fromLTRB(rect.left - left, rect.top - top, rect.right + right, rect.bottom + bottom);
   }
 
   EdgeDims operator -(EdgeDims other) {
diff --git a/packages/flutter/lib/src/painting/shadows.dart b/packages/flutter/lib/src/painting/shadows.dart
deleted file mode 100644
index 1a7d199..0000000
--- a/packages/flutter/lib/src/painting/shadows.dart
+++ /dev/null
@@ -1,29 +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 'dart:ui' as ui;
-
-/// A helper class to build a [ui.DrawLooper] for drawing shadows
-class ShadowDrawLooperBuilder {
-  ui.LayerDrawLooperBuilder _builder = new ui.LayerDrawLooperBuilder();
-
-  /// Adds a shadow with the given parameters.
-  void addShadow(ui.Offset offset, ui.Color color, double blur) {
-    _builder.addLayerOnTop(
-      new ui.DrawLooperLayerInfo()
-        ..setPaintBits(ui.PaintBits.all)
-        ..setOffset(offset)
-        ..setColorMode(ui.TransferMode.src),
-      new ui.Paint()
-        ..color = color
-        ..maskFilter = new ui.MaskFilter.blur(ui.BlurStyle.normal, blur)
-    );
-  }
-
-  /// Returns the draw looper built for the added shadows
-  ui.DrawLooper build() {
-    _builder.addLayerOnTop(new ui.DrawLooperLayerInfo(), new ui.Paint());
-    return _builder.build();
-  }
-}
diff --git a/packages/flutter/lib/src/painting/text_editing.dart b/packages/flutter/lib/src/painting/text_editing.dart
index 736582b..2ffa601 100644
--- a/packages/flutter/lib/src/painting/text_editing.dart
+++ b/packages/flutter/lib/src/painting/text_editing.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' show TextAffinity, TextPosition;
+import 'dart:ui' show hashValues, TextAffinity, TextPosition;
 
 export 'dart:ui' show TextAffinity, TextPosition;
 
@@ -50,6 +50,22 @@
     assert(isNormalized);
     return text.substring(start, end);
   }
+
+  bool operator ==(dynamic other) {
+    if (identical(this, other))
+      return true;
+    if (other is! TextRange)
+      return false;
+    TextRange typedOther = other;
+    return typedOther.start == start
+        && typedOther.end == end;
+  }
+
+  int get hashCode => hashValues(
+    start.hashCode,
+    end.hashCode
+  );
+
 }
 
 /// A range of text that represents a selection.
@@ -122,4 +138,23 @@
   String toString() {
     return '$runtimeType(baseOffset: $baseOffset, extentOffset: $extentOffset, affinity: $affinity, isDirectional: $isDirectional)';
   }
+
+  bool operator ==(dynamic other) {
+    if (identical(this, other))
+      return true;
+    if (other is! TextSelection)
+      return false;
+    TextSelection typedOther = other;
+    return typedOther.baseOffset == baseOffset
+        && typedOther.extentOffset == extentOffset
+        && typedOther.affinity == affinity
+        && typedOther.isDirectional == isDirectional;
+  }
+
+  int get hashCode => hashValues(
+    baseOffset.hashCode,
+    extentOffset.hashCode,
+    affinity.hashCode,
+    isDirectional.hashCode
+  );
 }
diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart
index 14bf7f1..7723474 100644
--- a/packages/flutter/lib/src/painting/text_painter.dart
+++ b/packages/flutter/lib/src/painting/text_painter.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Paragraph, ParagraphBuilder, ParagraphStyle, TextBox;
 
 import 'basic_types.dart';
 import 'text_editing.dart';
@@ -212,7 +212,7 @@
   }
 
   /// Paints the text onto the given canvas at the given offset.
-  void paint(ui.Canvas canvas, ui.Offset offset) {
+  void paint(Canvas canvas, Offset offset) {
     assert(!_needsLayout && "Please call layout() before paint() to position the text before painting it." is String);
     _paragraph.paint(canvas, offset);
   }
@@ -223,7 +223,7 @@
       return null;
     ui.TextBox box = boxes[0];
     double caretEnd = box.end;
-    double dx = box.direction == ui.TextDirection.rtl ? caretEnd : caretEnd - caretPrototype.width;
+    double dx = box.direction == TextDirection.rtl ? caretEnd : caretEnd - caretPrototype.width;
     return new Offset(dx, 0.0);
   }
 
@@ -233,7 +233,7 @@
       return null;
     ui.TextBox box = boxes[0];
     double caretStart = box.start;
-    double dx = box.direction == ui.TextDirection.rtl ? caretStart - caretPrototype.width : caretStart;
+    double dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart;
     return new Offset(dx, 0.0);
   }
 
diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart
index b0f506e..d03c1ad 100644
--- a/packages/flutter/lib/src/painting/text_style.dart
+++ b/packages/flutter/lib/src/painting/text_style.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show ParagraphStyle, TextStyle, lerpDouble;
 
 import 'basic_types.dart';
 
diff --git a/packages/flutter/lib/src/rendering/basic_types.dart b/packages/flutter/lib/src/rendering/basic_types.dart
index f3a756f..2beeee6 100644
--- a/packages/flutter/lib/src/rendering/basic_types.dart
+++ b/packages/flutter/lib/src/rendering/basic_types.dart
@@ -2,19 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-export 'dart:ui' show
-  Canvas,
-  Color,
-  ColorFilter,
-  Offset,
-  Paint,
-  Path,
-  Point,
-  Rect,
-  Size,
-  TransferMode,
-  VoidCallback;
-
 typedef void ValueChanged<T>(T value);
 
 /// A BitField over an enum (or other class whose values implement "index").
diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart
index 55c0c79..8769ba8 100644
--- a/packages/flutter/lib/src/rendering/binding.dart
+++ b/packages/flutter/lib/src/rendering/binding.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show window;
 
 import 'package:flutter/gestures.dart';
 import 'package:flutter/scheduler.dart';
diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart
index a88840a..8900948 100644
--- a/packages/flutter/lib/src/rendering/box.dart
+++ b/packages/flutter/lib/src/rendering/box.dart
@@ -3,19 +3,15 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
-import 'dart:ui' show hashValues;
+import 'dart:ui' as ui show lerpDouble;
 
 import 'package:flutter/animation.dart';
 import 'package:flutter/gestures.dart';
-import 'package:flutter/painting.dart';
 import 'package:vector_math/vector_math_64.dart';
 
 import 'debug.dart';
 import 'object.dart';
 
-export 'package:flutter/painting.dart' show EdgeDims, FractionalOffset, TextBaseline;
-
 // This class should only be used in debug builds
 class _DebugSize extends Size {
   _DebugSize(Size source, this._owner, this._canBeUsedByParent): super.copy(source);
@@ -837,7 +833,7 @@
   void debugPaintSize(PaintingContext context, Offset offset) {
     assert(() {
       Paint paint = new Paint()
-       ..style = ui.PaintingStyle.stroke
+       ..style = PaintingStyle.stroke
        ..strokeWidth = 1.0
        ..color = debugPaintSizeColor;
       context.canvas.drawRect((offset & size).deflate(0.5), paint);
@@ -847,7 +843,7 @@
   void debugPaintBaselines(PaintingContext context, Offset offset) {
     assert(() {
       Paint paint = new Paint()
-       ..style = ui.PaintingStyle.stroke
+       ..style = PaintingStyle.stroke
        ..strokeWidth = 0.25;
       Path path;
       // ideographic baseline
diff --git a/packages/flutter/lib/src/rendering/debug.dart b/packages/flutter/lib/src/rendering/debug.dart
index 550bfc3..a0cd337 100644
--- a/packages/flutter/lib/src/rendering/debug.dart
+++ b/packages/flutter/lib/src/rendering/debug.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 import 'dart:convert' show JSON;
 import 'dart:developer' as developer;
-import 'dart:ui' as ui;
 
 import 'package:flutter/painting.dart';
 import 'package:flutter/rendering.dart';
@@ -18,35 +17,35 @@
 bool debugPaintSizeEnabled = false;
 
 /// The color to use when painting RenderObject bounds.
-ui.Color debugPaintSizeColor = const ui.Color(0xFF00FFFF);
+Color debugPaintSizeColor = const Color(0xFF00FFFF);
 
 /// The color to use when painting some boxes that just add space (e.g. an empty
 /// RenderConstrainedBox or RenderPadding).
-ui.Color debugPaintSpacingColor = const ui.Color(0x90909090);
+Color debugPaintSpacingColor = const Color(0x90909090);
 
 /// The color to use when painting RenderPadding edges.
-ui.Color debugPaintPaddingColor = const ui.Color(0x900090FF);
+Color debugPaintPaddingColor = const Color(0x900090FF);
 
 /// The color to use when painting RenderPadding edges.
-ui.Color debugPaintPaddingInnerEdgeColor = const ui.Color(0xFF0090FF);
+Color debugPaintPaddingInnerEdgeColor = const Color(0xFF0090FF);
 
 /// The color to use when painting the arrows used to show RenderPositionedBox alignment.
-ui.Color debugPaintArrowColor = const ui.Color(0xFFFFFF00);
+Color debugPaintArrowColor = const Color(0xFFFFFF00);
 
 /// Causes each RenderBox to paint a line at each of its baselines.
 bool debugPaintBaselinesEnabled = false;
 
 /// The color to use when painting alphabetic baselines.
-ui.Color debugPaintAlphabeticBaselineColor = const ui.Color(0xFF00FF00);
+Color debugPaintAlphabeticBaselineColor = const Color(0xFF00FF00);
 
 /// The color ot use when painting ideographic baselines.
-ui.Color debugPaintIdeographicBaselineColor = const ui.Color(0xFFFFD000);
+Color debugPaintIdeographicBaselineColor = const Color(0xFFFFD000);
 
 /// Causes each Layer to paint a box around its bounds.
 bool debugPaintLayerBordersEnabled = false;
 
 /// The color to use when painting Layer borders.
-ui.Color debugPaintLayerBordersColor = const ui.Color(0xFFFF9800);
+Color debugPaintLayerBordersColor = const Color(0xFFFF9800);
 
 /// Causes RenderBox objects to flash while they are being tapped.
 bool debugPaintPointersEnabled = false;
@@ -55,7 +54,7 @@
 int debugPaintPointersColorValue = 0x00BBBB;
 
 /// The color to use when painting RenderError boxes in checked mode.
-ui.Color debugErrorBoxColor = const ui.Color(0xFFFF0000);
+Color debugErrorBoxColor = const Color(0xFFFF0000);
 
 /// Overlay a rotating set of colors when repainting layers in checked mode.
 bool debugEnableRepaintRainbox = false;
diff --git a/packages/flutter/lib/src/rendering/editable_line.dart b/packages/flutter/lib/src/rendering/editable_line.dart
index b124ff9..bc4ad25 100644
--- a/packages/flutter/lib/src/rendering/editable_line.dart
+++ b/packages/flutter/lib/src/rendering/editable_line.dart
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Paragraph, ParagraphBuilder, ParagraphStyle, TextBox;
 
 import 'package:flutter/gestures.dart';
-import 'package:flutter/painting.dart';
 
+import 'basic_types.dart';
 import 'box.dart';
 import 'object.dart';
-import 'paragraph.dart';
 
 const _kCaretGap = 1.0; // pixels
 const _kCaretHeightOffset = 2.0; // pixels
diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart
index 5b18a69..597dfa2 100644
--- a/packages/flutter/lib/src/rendering/image.dart
+++ b/packages/flutter/lib/src/rendering/image.dart
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
-import 'package:flutter/painting.dart';
+import 'dart:ui' as ui show Image;
 
 import 'box.dart';
 import 'object.dart';
diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart
index 3c96290..5342d7a 100644
--- a/packages/flutter/lib/src/rendering/layer.dart
+++ b/packages/flutter/lib/src/rendering/layer.dart
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Picture, SceneBuilder;
+import 'dart:ui' show Offset;
 
+import 'package:flutter/painting.dart';
 import 'package:vector_math/vector_math_64.dart';
 import 'package:mojo_services/mojo/ui/layouts.mojom.dart' as mojom;
 
-import 'basic_types.dart';
 import 'debug.dart';
 
-export 'basic_types.dart';
-
 /// A composited layer
 ///
 /// During painting, the render tree generates a tree of composited layers that
@@ -317,7 +316,7 @@
   ClipRRectLayer({ this.clipRRect });
 
   /// The rounded-rect to clip in the parent's coordinate system
-  ui.RRect clipRRect;
+  RRect clipRRect;
   // TODO(abarth): Why is the rounded-rect in the parent's coordinate system
   // instead of in the coordinate system of this layer?
 
@@ -403,7 +402,7 @@
   ShaderMaskLayer({ this.shader, this.maskRect, this.transferMode });
 
   /// The shader to apply to the children.
-  ui.Shader shader;
+  Shader shader;
 
   /// The size of the shader.
   Rect maskRect;
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index f92a4aa..ec8cf01 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:developer';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show PictureRecorder;
 
 import 'package:flutter/gestures.dart';
 import 'package:flutter/painting.dart';
@@ -18,8 +18,8 @@
 import 'semantics.dart';
 import 'binding.dart';
 
-export 'layer.dart';
 export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
+export 'package:flutter/painting.dart';
 
 /// Base class for data associated with a [RenderObject] by its parent.
 ///
@@ -163,7 +163,7 @@
         canvas.drawRect(_paintBounds, new Paint()..color = debugCurrentRepaintColor.toColor());
       if (debugPaintLayerBordersEnabled) {
         Paint paint = new Paint()
-          ..style = ui.PaintingStyle.stroke
+          ..style = PaintingStyle.stroke
           ..strokeWidth = 1.0
           ..color = debugPaintLayerBordersColor;
         canvas.drawRect(_paintBounds, paint);
@@ -223,9 +223,9 @@
   /// This function will call painter synchronously with a painting context that
   /// is clipped by the given clip. The given clip should not incorporate the
   /// painting offset.
-  void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, ui.RRect clipRRect, PaintingContextCallback painter) {
+  void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter) {
     Rect offsetBounds = bounds.shift(offset);
-    ui.RRect offsetClipRRect = clipRRect.shift(offset);
+    RRect offsetClipRRect = clipRRect.shift(offset);
     if (needsCompositing) {
       _stopRecordingIfNeeded();
       ClipRRectLayer clipLayer = new ClipRRectLayer(clipRRect: offsetClipRRect);
@@ -305,7 +305,7 @@
   ///
   /// This function will call painter synchronously with a painting context that
   /// will be masked with the given shader.
-  void pushShaderMask(Offset offset, ui.Shader shader, Rect maskRect, TransferMode transferMode, PaintingContextCallback painter) {
+  void pushShaderMask(Offset offset, Shader shader, Rect maskRect, TransferMode transferMode, PaintingContextCallback painter) {
     _stopRecordingIfNeeded();
     ShaderMaskLayer shaderLayer = new ShaderMaskLayer(
       shader: shader,
diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart
index 9c7df51..330af42 100644
--- a/packages/flutter/lib/src/rendering/paragraph.dart
+++ b/packages/flutter/lib/src/rendering/paragraph.dart
@@ -2,24 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/painting.dart';
-
 import 'box.dart';
 import 'object.dart';
 import 'semantics.dart';
 
-export 'package:flutter/painting.dart' show
-  FontStyle,
-  FontWeight,
-  PlainTextSpan,
-  StyledTextSpan,
-  TextAlign,
-  TextBaseline,
-  TextDecoration,
-  TextDecorationStyle,
-  TextSpan,
-  TextStyle;
-
 /// A render object that displays a paragraph of text
 class RenderParagraph extends RenderBox {
 
diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart
index 4d81aaa..e4b183b 100644
--- a/packages/flutter/lib/src/rendering/proxy_box.dart
+++ b/packages/flutter/lib/src/rendering/proxy_box.dart
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
-import 'package:flutter/painting.dart';
 import 'package:flutter/gestures.dart';
 import 'package:vector_math/vector_math_64.dart';
 
+import 'basic_types.dart';
 import 'box.dart';
 import 'debug.dart';
 import 'object.dart';
@@ -19,7 +17,6 @@
   PointerMoveEvent,
   PointerUpEvent,
   PointerCancelEvent;
-export 'package:flutter/painting.dart' show Decoration, BoxDecoration;
 
 /// A base class for render objects that resemble their children.
 ///
@@ -642,7 +639,7 @@
   }
 }
 
-typedef ui.Shader ShaderCallback(Rect bounds);
+typedef Shader ShaderCallback(Rect bounds);
 
 class RenderShaderMask extends RenderProxyBox {
   RenderShaderMask({ RenderBox child, ShaderCallback shaderCallback, TransferMode transferMode })
@@ -805,7 +802,7 @@
   void paint(PaintingContext context, Offset offset) {
     if (child != null) {
       Rect rect = Point.origin & size;
-      ui.RRect rrect = new ui.RRect.fromRectXY(rect, xRadius, yRadius);
+      RRect rrect = new RRect.fromRectXY(rect, xRadius, yRadius);
       context.pushClipRRect(needsCompositing, offset, rect, rrect, super.paint);
     }
   }
diff --git a/packages/flutter/lib/src/rendering/shifted_box.dart b/packages/flutter/lib/src/rendering/shifted_box.dart
index 73d6357..0718aed 100644
--- a/packages/flutter/lib/src/rendering/shifted_box.dart
+++ b/packages/flutter/lib/src/rendering/shifted_box.dart
@@ -3,9 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
-
-import 'package:flutter/painting.dart';
 
 import 'box.dart';
 import 'debug.dart';
@@ -300,7 +297,7 @@
       if (child != null && !child.size.isEmpty) {
         Path path;
         paint = new Paint()
-          ..style = ui.PaintingStyle.stroke
+          ..style = PaintingStyle.stroke
           ..strokeWidth = 1.0
           ..color = debugPaintArrowColor;
         path = new Path();
diff --git a/packages/flutter/lib/src/rendering/view.dart b/packages/flutter/lib/src/rendering/view.dart
index abdcbf4..d12b3b7 100644
--- a/packages/flutter/lib/src/rendering/view.dart
+++ b/packages/flutter/lib/src/rendering/view.dart
@@ -3,9 +3,8 @@
 // found in the LICENSE file.
 
 import 'dart:developer';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Scene, SceneBuilder, window;
 
-import 'package:flutter/painting.dart';
 import 'package:flutter/scheduler.dart';
 import 'package:vector_math/vector_math_64.dart';
 
diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart
index 967eaba..e1fee2a 100644
--- a/packages/flutter/lib/src/rendering/viewport.dart
+++ b/packages/flutter/lib/src/rendering/viewport.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show window;
 
 import 'package:vector_math/vector_math_64.dart';
 
diff --git a/packages/flutter/lib/src/scheduler/scheduler.dart b/packages/flutter/lib/src/scheduler/scheduler.dart
index 4da82e4..22387c4 100644
--- a/packages/flutter/lib/src/scheduler/scheduler.dart
+++ b/packages/flutter/lib/src/scheduler/scheduler.dart
@@ -5,11 +5,14 @@
 import 'dart:async';
 import 'dart:collection';
 import 'dart:developer';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show window;
+import 'dart:ui' show VoidCallback;
 
 import 'package:collection/collection.dart';
 import 'package:flutter/services.dart';
 
+export 'dart:ui' show VoidCallback;
+
 /// Slows down animations by this factor to help in development.
 double timeDilation = 1.0;
 
@@ -32,7 +35,7 @@
 ///
 /// Combines the task and its priority.
 class _TaskEntry {
-  final ui.VoidCallback task;
+  final VoidCallback task;
   final int priority;
 
   const _TaskEntry(this.task, this.priority);
@@ -110,7 +113,7 @@
   bool _hasRequestedABeginFrameCallback = false;
 
   /// Schedules the given [task] with the given [priority].
-  void scheduleTask(ui.VoidCallback task, Priority priority) {
+  void scheduleTask(VoidCallback task, Priority priority) {
     bool isFirstTask = _taskQueue.isEmpty;
     _taskQueue.add(new _TaskEntry(task, priority._value));
     if (isFirstTask)
diff --git a/packages/flutter/lib/src/animation/ticker.dart b/packages/flutter/lib/src/scheduler/ticker.dart
similarity index 97%
rename from packages/flutter/lib/src/animation/ticker.dart
rename to packages/flutter/lib/src/scheduler/ticker.dart
index 9e48454..9e6be89 100644
--- a/packages/flutter/lib/src/animation/ticker.dart
+++ b/packages/flutter/lib/src/scheduler/ticker.dart
@@ -4,7 +4,7 @@
 
 import 'dart:async';
 
-import 'package:flutter/scheduler.dart';
+import 'scheduler.dart';
 
 typedef TickerCallback(Duration elapsed);
 
diff --git a/packages/flutter/lib/src/services/image_decoder.dart b/packages/flutter/lib/src/services/image_decoder.dart
index fcba7ec..8a60e41 100644
--- a/packages/flutter/lib/src/services/image_decoder.dart
+++ b/packages/flutter/lib/src/services/image_decoder.dart
@@ -4,7 +4,7 @@
 
 import 'dart:async';
 import 'dart:typed_data';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image, decodeImageFromDataPipe, decodeImageFromList;
 
 import 'package:mojo/core.dart' show MojoDataPipeConsumer;
 
diff --git a/packages/flutter/lib/src/services/image_resource.dart b/packages/flutter/lib/src/services/image_resource.dart
index 75d4f0d..c6d0e9e 100644
--- a/packages/flutter/lib/src/services/image_resource.dart
+++ b/packages/flutter/lib/src/services/image_resource.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image;
 
 import 'print.dart';
 
diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart
index a47685e..0db20a8 100644
--- a/packages/flutter/lib/src/widgets/basic.dart
+++ b/packages/flutter/lib/src/widgets/basic.dart
@@ -2,72 +2,46 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image;
 
 import 'package:flutter/rendering.dart';
 import 'package:flutter/services.dart';
 
 import 'framework.dart';
 
+export 'package:flutter/animation.dart';
+export 'package:flutter/painting.dart';
 export 'package:flutter/rendering.dart' show
-    BackgroundImage,
-    Border,
-    BorderSide,
+    Axis,
     BoxConstraints,
-    BoxDecoration,
-    BoxShadow,
-    BoxShape,
-    Canvas,
-    Color,
-    ColorFilter,
     CustomClipper,
     CustomPainter,
-    Decoration,
-    DecorationPosition,
-    EdgeDims,
+    FixedColumnCountGridDelegate,
     FlexAlignItems,
     FlexDirection,
     FlexJustifyContent,
-    FixedColumnCountGridDelegate,
-    FontStyle,
-    FontWeight,
-    FractionalOffset,
-    Gradient,
+    FractionalOffsetTween,
     GridDelegate,
     HitTestBehavior,
-    ImageFit,
-    ImageRepeat,
-    InputEvent,
-    LinearGradient,
-    Matrix4,
     MaxTileWidthGridDelegate,
-    Offset,
+    MultiChildLayoutDelegate,
     OneChildLayoutDelegate,
-    Paint,
-    Path,
+    Painter,
+    PaintingContext,
     PlainTextSpan,
-    Point,
     PointerCancelEvent,
+    PointerCancelEventListener,
     PointerDownEvent,
+    PointerDownEventListener,
     PointerEvent,
     PointerMoveEvent,
+    PointerMoveEventListener,
     PointerUpEvent,
-    RadialGradient,
-    Rect,
-    Axis,
-    Size,
-    StyledTextSpan,
-    TextAlign,
-    TextBaseline,
-    TextDecoration,
-    TextDecorationStyle,
-    TextSpan,
-    TextStyle,
-    TransferMode,
+    PointerUpEventListener,
+    RelativeRect,
+    ShaderCallback,
     ValueChanged,
-    ViewportAnchor,
-    VoidCallback;
-
+    ViewportAnchor;
 
 // PAINTING NODES
 
diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart
index 96ec7f4..43a0abb 100644
--- a/packages/flutter/lib/src/widgets/binding.dart
+++ b/packages/flutter/lib/src/widgets/binding.dart
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
 import 'dart:developer';
+import 'dart:ui' as ui show window;
+import 'dart:ui' show AppLifecycleState, Locale;
 
 import 'package:flutter/gestures.dart';
 import 'package:flutter/rendering.dart';
@@ -12,11 +13,13 @@
 
 import 'framework.dart';
 
+export 'dart:ui' show AppLifecycleState, Locale;
+
 class BindingObserver {
   bool didPopRoute() => false;
   void didChangeMetrics() { }
-  void didChangeLocale(ui.Locale locale) { }
-  void didChangeAppLifecycleState(ui.AppLifecycleState state) { }
+  void didChangeLocale(Locale locale) { }
+  void didChangeAppLifecycleState(AppLifecycleState state) { }
 }
 
 /// A concrete binding for applications based on the Widgets framework.
@@ -69,7 +72,7 @@
     dispatchLocaleChanged(ui.window.locale);
   }
 
-  void dispatchLocaleChanged(ui.Locale locale) {
+  void dispatchLocaleChanged(Locale locale) {
     for (BindingObserver observer in _observers)
       observer.didChangeLocale(locale);
   }
@@ -82,7 +85,7 @@
     activity.finishCurrentActivity();
   }
 
-  void handleAppLifecycleStateChanged(ui.AppLifecycleState state) {
+  void handleAppLifecycleStateChanged(AppLifecycleState state) {
     for (BindingObserver observer in _observers)
       observer.didChangeAppLifecycleState(state);
   }
diff --git a/packages/flutter/lib/src/widgets/checked_mode_banner.dart b/packages/flutter/lib/src/widgets/checked_mode_banner.dart
index cad5edd..e5e0faa 100644
--- a/packages/flutter/lib/src/widgets/checked_mode_banner.dart
+++ b/packages/flutter/lib/src/widgets/checked_mode_banner.dart
@@ -3,10 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
-
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
 
 import 'basic.dart';
 import 'framework.dart';
@@ -37,7 +33,7 @@
   void paint(Canvas canvas, Size size) {
     final Paint paintShadow = new Paint()
       ..color = const Color(0x7F000000)
-      ..maskFilter = new ui.MaskFilter.blur(ui.BlurStyle.normal, kShadowBlur);
+      ..maskFilter = new MaskFilter.blur(BlurStyle.normal, kShadowBlur);
     final Paint paintBanner = new Paint()
       ..color = kColor;
     canvas
diff --git a/packages/flutter/lib/src/widgets/dismissable.dart b/packages/flutter/lib/src/widgets/dismissable.dart
index 19e4a08..a1f1edd 100644
--- a/packages/flutter/lib/src/widgets/dismissable.dart
+++ b/packages/flutter/lib/src/widgets/dismissable.dart
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-
-import 'package:flutter/animation.dart';
-
 import 'basic.dart';
 import 'transitions.dart';
 import 'framework.dart';
@@ -186,7 +182,7 @@
       _dismissController.value = _dragExtent.abs() / _size.width;
   }
 
-  bool _isFlingGesture(ui.Offset velocity) {
+  bool _isFlingGesture(Offset velocity) {
     double vx = velocity.dx;
     double vy = velocity.dy;
     if (_directionIsYAxis) {
@@ -215,7 +211,7 @@
     return false;
   }
 
-  void _handleDragEnd(ui.Offset velocity) {
+  void _handleDragEnd(Offset velocity) {
     if (!_isActive || _dismissController.isAnimating)
       return;
     setState(() {
diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart
index 67944e4..b7aa95b 100644
--- a/packages/flutter/lib/src/widgets/drag_target.dart
+++ b/packages/flutter/lib/src/widgets/drag_target.dart
@@ -16,7 +16,6 @@
 typedef bool DragTargetWillAccept<T>(T data);
 typedef void DragTargetAccept<T>(T data);
 typedef Widget DragTargetBuilder<T>(BuildContext context, List<T> candidateData, List<dynamic> rejectedData);
-typedef void DragStartCallback(Point position, int pointer);
 
 /// Where the [Draggable] should be anchored during a drag.
 enum DragAnchor {
@@ -81,11 +80,9 @@
   /// dragged at a time.
   final int maxSimultaneousDrags;
 
-  /// Should return a GestureRecognizer instance that is configured to call the starter
-  /// argument when the drag is to begin. The arena for the pointer must not yet have
-  /// resolved at the time that the callback is invoked, because the draggable itself
-  /// is going to attempt to win the pointer's arena in that case.
-  GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter);
+  /// Should return a new MultiDragGestureRecognizer instance
+  /// constructed with the given arguments.
+  MultiDragGestureRecognizer createRecognizer(PointerRouter router, GestureArena arena, GestureMultiDragStartCallback starter);
 
   _DraggableState<T> createState() => new _DraggableState<T>();
 }
@@ -112,11 +109,11 @@
     maxSimultaneousDrags: maxSimultaneousDrags
   );
 
-  GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) {
-    return new MultiTapGestureRecognizer(
-      router: router,
-      gestureArena: Gesturer.instance.gestureArena,
-      onTapDown: starter
+  MultiDragGestureRecognizer createRecognizer(PointerRouter router, GestureArena arena, GestureMultiDragStartCallback starter) {
+    return new ImmediateMultiDragGestureRecognizer(
+      pointerRouter: router,
+      gestureArena: arena,
+      onStart: starter
     );
   }
 }
@@ -143,50 +140,44 @@
     maxSimultaneousDrags: maxSimultaneousDrags
   );
 
-  GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) {
-    return new MultiTapGestureRecognizer(
-      router: router,
-      gestureArena: Gesturer.instance.gestureArena,
-      longTapDelay: kLongPressTimeout,
-      onLongTapDown: (Point position, int pointer) {
-        userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
-        starter(position, pointer);
+  MultiDragGestureRecognizer createRecognizer(PointerRouter router, GestureArena arena, GestureMultiDragStartCallback starter) {
+    return new DelayedMultiDragGestureRecognizer(
+      pointerRouter: router,
+      gestureArena: arena,
+      delay: kLongPressTimeout,
+      onStart: (Point position) {
+        Drag result = starter(position);
+        if (result != null)
+          userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
+        return result;
       }
     );
   }
 }
 
-class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArenaMember {
-
-  PointerRouter get router => Gesturer.instance.pointerRouter;
+class _DraggableState<T> extends State<DraggableBase<T>> {
 
   void initState() {
     super.initState();
-    _recognizer = config.createRecognizer(router, _startDrag);
+    _recognizer = config.createRecognizer(
+      Gesturer.instance.pointerRouter,
+      Gesturer.instance.gestureArena,
+      _startDrag
+    );
   }
 
   GestureRecognizer _recognizer;
-  Map<int, GestureArenaEntry> _activePointers = <int, GestureArenaEntry>{};
   int _activeCount = 0;
 
   void _routePointer(PointerEvent event) {
-    _activePointers[event.pointer] = Gesturer.instance.gestureArena.add(event.pointer, this);
+    if (config.maxSimultaneousDrags != null && _activeCount >= config.maxSimultaneousDrags)
+      return;
     _recognizer.addPointer(event);
   }
 
-  void acceptGesture(int pointer) {
-    _activePointers.remove(pointer);
-  }
-
-  void rejectGesture(int pointer) {
-    _activePointers.remove(pointer);
-  }
-
-  void _startDrag(Point position, int pointer) {
+  _DragAvatar _startDrag(Point position) {
     if (config.maxSimultaneousDrags != null && _activeCount >= config.maxSimultaneousDrags)
-      return;
-    assert(_activePointers.containsKey(pointer));
-    _activePointers[pointer].resolve(GestureDisposition.accepted);
+      return null;
     Point dragStartPoint;
     switch (config.dragAnchor) {
       case DragAnchor.child:
@@ -200,9 +191,7 @@
     setState(() {
       _activeCount += 1;
     });
-    new _DragAvatar<T>(
-      pointer: pointer,
-      router: router,
+    return new _DragAvatar<T>(
       overlay: Overlay.of(context),
       data: config.data,
       initialPosition: position,
@@ -305,10 +294,8 @@
 // overlay goes away, or maybe even if the Draggable that created goes away.
 // This will probably need to be changed once we have more experience with using
 // this widget.
-class _DragAvatar<T> {
+class _DragAvatar<T> extends Drag {
   _DragAvatar({
-    this.pointer,
-    this.router,
     OverlayState overlay,
     this.data,
     Point initialPosition,
@@ -317,19 +304,15 @@
     this.feedbackOffset: Offset.zero,
     this.onDragEnd
   }) {
-    assert(pointer != null);
-    assert(router != null);
     assert(overlay != null);
     assert(dragStartPoint != null);
     assert(feedbackOffset != null);
-    router.addRoute(pointer, handleEvent);
     _entry = new OverlayEntry(builder: _build);
     overlay.insert(_entry);
+    _position = initialPosition;
     update(initialPosition);
   }
 
-  final int pointer;
-  final PointerRouter router;
   final T data;
   final Point dragStartPoint;
   final Widget feedback;
@@ -338,18 +321,20 @@
 
   _DragTargetState _activeTarget;
   bool _activeTargetWillAcceptDrop = false;
+  Point _position;
   Offset _lastOffset;
   OverlayEntry _entry;
 
-  void handleEvent(PointerEvent event) {
-    if (event is PointerUpEvent) {
-      update(event.position);
-      finish(_DragEndKind.dropped);
-    } else if (event is PointerCancelEvent) {
-      finish(_DragEndKind.canceled);
-    } else if (event is PointerMoveEvent) {
-      update(event.position);
-    }
+  // Drag API
+  void move(Offset offset) {
+    _position += offset;
+    update(_position);
+  }
+  void end(Offset velocity) {
+    finish(_DragEndKind.dropped);
+  }
+  void cancel() {
+    finish(_DragEndKind.canceled);
   }
 
   void update(Point globalPosition) {
@@ -390,7 +375,6 @@
     _activeTargetWillAcceptDrop = false;
     _entry.remove();
     _entry = null;
-    router.removeRoute(pointer, handleEvent);
     if (onDragEnd != null)
       onDragEnd();
   }
diff --git a/packages/flutter/lib/src/widgets/editable.dart b/packages/flutter/lib/src/widgets/editable.dart
index 3eb9e8e..b1bf089 100644
--- a/packages/flutter/lib/src/widgets/editable.dart
+++ b/packages/flutter/lib/src/widgets/editable.dart
@@ -4,16 +4,18 @@
 
 import 'dart:async';
 
+import 'package:flutter/rendering.dart' show RenderEditableLine;
 import 'package:sky_services/editing/editing.mojom.dart' as mojom;
-import 'package:flutter/painting.dart';
-import 'package:flutter/rendering.dart';
+import 'package:flutter/services.dart';
 
 import 'basic.dart';
 import 'framework.dart';
+import 'focus.dart';
 import 'scrollable.dart';
 import 'scroll_behavior.dart';
 
 export 'package:flutter/painting.dart' show TextSelection;
+export 'package:sky_services/editing/editing.mojom.dart' show KeyboardType;
 
 const Duration _kCursorBlinkHalfPeriod = const Duration(milliseconds: 500);
 
@@ -28,17 +30,16 @@
 
 class _KeyboardClientImpl implements mojom.KeyboardClient {
   _KeyboardClientImpl({
-    String text: '',
-    TextSelection selection,
+    this.inputValue,
     this.onUpdated,
     this.onSubmitted
-  }) : text = text, selection = selection ?? new TextSelection.collapsed(offset: text.length) {
+  }) {
+    assert(inputValue != null);
     assert(onUpdated != null);
     assert(onSubmitted != null);
   }
 
-  /// The current text being edited.
-  String text;
+  InputValue inputValue;
 
   /// Called whenever the text changes.
   final VoidCallback onUpdated;
@@ -46,12 +47,6 @@
   /// Called whenever the user indicates they are done editing the string.
   final VoidCallback onSubmitted;
 
-  // The range of text that is still being composed.
-  TextRange composing = TextRange.empty;
-
-  /// The range of text that is currently selected.
-  TextSelection selection;
-
   /// A keyboard client stub that can be attached to a keyboard service.
   mojom.KeyboardClientStub createStub() {
     return new mojom.KeyboardClientStub.unbound()..impl = this;
@@ -59,69 +54,82 @@
 
   mojom.EditingState get editingState {
     return new mojom.EditingState()
-      ..text = text
-      ..selectionBase = selection.baseOffset
-      ..selectionExtent = selection.extentOffset
-      ..selectionAffinity = mojom.TextAffinity.values[selection.affinity.index]
-      ..selectionIsDirectional = selection.isDirectional
-      ..composingBase = composing.start
-      ..composingExtent = composing.end;
+      ..text = inputValue.text
+      ..selectionBase = inputValue.selection.baseOffset
+      ..selectionExtent = inputValue.selection.extentOffset
+      ..selectionAffinity = mojom.TextAffinity.values[inputValue.selection.affinity.index]
+      ..selectionIsDirectional = inputValue.selection.isDirectional
+      ..composingBase = inputValue.composing.start
+      ..composingExtent = inputValue.composing.end;
   }
 
   void updateEditingState(mojom.EditingState state) {
-    text = state.text;
-    selection = _getTextSelectionFromEditingState(state);
-    composing = new TextRange(start: state.composingBase, end: state.composingExtent);
+    inputValue = new InputValue(
+      text: state.text,
+      selection: _getTextSelectionFromEditingState(state),
+      composing: new TextRange(start: state.composingBase, end: state.composingExtent)
+    );
     onUpdated();
   }
 
+  void clearComposing() {
+    inputValue = inputValue.copyWith(composing: TextRange.empty);
+  }
+
   void submit(mojom.SubmitAction action) {
-    composing = TextRange.empty;
+    clearComposing();
     onSubmitted();
   }
 }
 
-/// A string that can be manipulated by a keyboard.
-///
-/// Can be displayed with [RawEditableLine]. For a more featureful input widget,
-/// consider using [Input].
-class EditableString {
-  EditableString({
-    String text: '',
-    TextSelection selection,
-    VoidCallback onUpdated,
-    VoidCallback onSubmitted
-  }) : _client = new _KeyboardClientImpl(
-      text: text,
-      selection: selection,
-      onUpdated: onUpdated,
-      onSubmitted: onSubmitted
-    );
-
-  final _KeyboardClientImpl _client;
+/// Configurable state of an input field.
+class InputValue {
+  const InputValue({
+    this.text: '',
+    this.selection: const TextSelection.collapsed(offset: -1),
+    this.composing: TextRange.empty
+  });
 
   /// The current text being edited.
-  String get text => _client.text;
-
-  // The range of text that is still being composed.
-  TextRange get composing => _client.composing;
+  final String text;
 
   /// The range of text that is currently selected.
-  TextSelection get selection => _client.selection;
+  final TextSelection selection;
 
-  void setSelection(TextSelection selection) {
-    _client.selection = selection;
-  }
+  // The range of text that is still being composed.
+  final TextRange composing;
 
-  mojom.EditingState get editingState => _client.editingState;
+  static const InputValue empty = const InputValue();
 
-  /// A keyboard client stub that can be attached to a keyboard service.
-  ///
-  /// See [Keyboard].
-  mojom.KeyboardClientStub createStub() => _client.createStub();
+  String toString() => '$runtimeType(text: $text, selection: $selection, composing: $composing)';
 
-  void didDetachKeyboard() {
-    _client.composing = TextRange.empty;
+  bool operator ==(dynamic other) {
+    if (identical(this, other))
+      return true;
+    if (other is! InputValue)
+      return false;
+    InputValue typedOther = other;
+    return typedOther.text == text
+        && typedOther.selection == selection
+        && typedOther.composing == composing;
+  }  
+
+  int get hashCode => hashValues(
+    text.hashCode,
+    selection.hashCode,
+    composing.hashCode
+  );
+
+  InputValue copyWith({
+    String text,
+    TextSelection selection,
+    TextRange composing
+  }) {
+    return new InputValue (
+      text: text ?? this.text, 
+      selection: selection ?? this.selection,
+      composing: composing ?? this.composing
+    );
   }
 }
 
@@ -129,27 +137,29 @@
 ///
 /// This control is not intended to be used directly. Instead, consider using
 /// [Input], which provides focus management and material design.
-class RawEditableLine extends Scrollable {
-  RawEditableLine({
+class RawInputLine extends Scrollable {
+  RawInputLine({
     Key key,
     this.value,
-    this.focused: false,
+    this.focusKey,
     this.hideText: false,
     this.style,
     this.cursorColor,
     this.selectionColor,
-    this.onSelectionChanged
+    this.keyboardType,
+    this.onChanged,
+    this.onSubmitted
   }) : super(
     key: key,
     initialScrollOffset: 0.0,
     scrollDirection: Axis.horizontal
   );
 
-  /// The editable string being displayed in this widget.
-  final EditableString value;
+  /// The string being displayed in this widget.
+  final InputValue value;
 
-  /// Whether this widget is focused.
-  final bool focused;
+  /// Key of the enclosing widget that holds the focus.
+  final GlobalKey focusKey;
 
   /// Whether to hide the text being edited (e.g., for passwords).
   final bool hideText;
@@ -163,22 +173,51 @@
   /// The color to use when painting the selection.
   final Color selectionColor;
 
-  /// Called when the user requests a change to the selection.
-  final ValueChanged<TextSelection> onSelectionChanged;
+  /// The type of keyboard to use for editing the text.
+  final KeyboardType keyboardType;
 
-  RawEditableTextState createState() => new RawEditableTextState();
+  /// Called when the text being edited changes.
+  final ValueChanged<InputValue> onChanged;
+
+  /// Called when the user indicates that they are done editing the text in the field.
+  final ValueChanged<InputValue> onSubmitted;
+
+  RawInputLineState createState() => new RawInputLineState();
 }
 
-class RawEditableTextState extends ScrollableState<RawEditableLine> {
+class RawInputLineState extends ScrollableState<RawInputLine> {
   Timer _cursorTimer;
   bool _showCursor = false;
 
   double _contentWidth = 0.0;
   double _containerWidth = 0.0;
 
+  _KeyboardClientImpl _keyboardClient;
+  KeyboardHandle _keyboardHandle;
+
   ScrollBehavior createScrollBehavior() => new BoundedBehavior();
   BoundedBehavior get scrollBehavior => super.scrollBehavior;
 
+  void initState() {
+    super.initState();
+    _keyboardClient = new _KeyboardClientImpl(
+      inputValue: config.value,
+      onUpdated: _handleTextUpdated,
+      onSubmitted: _handleTextSubmitted
+    );
+  }
+
+  void didUpdateConfig(RawInputLine oldConfig) {
+    if (_keyboardClient.inputValue != config.value) {
+      _keyboardClient.inputValue = config.value;
+      if (_isAttachedToKeyboard) {
+        _keyboardHandle.setEditingState(_keyboardClient.editingState);
+      }
+    }
+  }
+
+  bool get _isAttachedToKeyboard => _keyboardHandle != null && _keyboardHandle.attached;
+
   void _handleContainerSizeChanged(Size newSize) {
     _containerWidth = newSize.width;
     _updateScrollBehavior();
@@ -199,6 +238,48 @@
     ));
   }
 
+  void _attachOrDetachKeyboard(bool focused) {
+    if (focused && !_isAttachedToKeyboard) {
+      _keyboardHandle = keyboard.attach(_keyboardClient.createStub(),
+                                        new mojom.KeyboardConfiguration()
+                                          ..type = config.keyboardType);
+      _keyboardHandle.setEditingState(_keyboardClient.editingState);
+      _keyboardHandle.show();
+    } else if (!focused && _isAttachedToKeyboard) {
+      _keyboardHandle.release();
+      _keyboardHandle = null;
+      _keyboardClient.clearComposing();
+    }
+  }
+
+  void requestKeyboard() {
+    if (_isAttachedToKeyboard) {
+      _keyboardHandle.show();
+    } else {
+      Focus.moveTo(config.focusKey);
+    }
+  }
+
+  void _handleTextUpdated() {
+    if (config.onChanged != null)
+      config.onChanged(_keyboardClient.inputValue);
+  }
+
+  void _handleTextSubmitted() {
+    Focus.clear(context);
+    if (config.onSubmitted != null)
+      config.onSubmitted(_keyboardClient.inputValue);
+  }
+
+  void _handleSelectionChanged(TextSelection selection) {
+    // Note that this will show the keyboard for all selection changes on the
+    // EditableLineWidget, not just changes triggered by user gestures.
+    requestKeyboard();
+
+    if (config.onChanged != null)
+      config.onChanged(_keyboardClient.inputValue.copyWith(selection: selection));
+  }
+
   /// Whether the blinking cursor is actually visible at this precise moment
   /// (it's hidden half the time, since it blinks).
   bool get cursorCurrentlyVisible => _showCursor;
@@ -220,6 +301,8 @@
   }
 
   void dispose() {
+    if (_isAttachedToKeyboard)
+      _keyboardHandle.release();
     if (_cursorTimer != null)
       _stopCursorTimer();
     super.dispose();
@@ -233,12 +316,15 @@
 
   Widget buildContent(BuildContext context) {
     assert(config.style != null);
-    assert(config.focused != null);
+    assert(config.focusKey != null);
     assert(config.cursorColor != null);
 
-    if (_cursorTimer == null && config.focused && config.value.selection.isCollapsed)
+    bool focused = Focus.at(config.focusKey.currentContext);
+    _attachOrDetachKeyboard(focused);
+
+    if (_cursorTimer == null && focused && config.value.selection.isCollapsed)
       _startCursorTimer();
-    else if (_cursorTimer != null && (!config.focused || !config.value.selection.isCollapsed))
+    else if (_cursorTimer != null && (!focused || !config.value.selection.isCollapsed))
       _stopCursorTimer();
 
     return new SizeObserver(
@@ -251,7 +337,7 @@
         selectionColor: config.selectionColor,
         hideText: config.hideText,
         onContentSizeChanged: _handleContentSizeChanged,
-        onSelectionChanged: config.onSelectionChanged,
+        onSelectionChanged: _handleSelectionChanged,
         paintOffset: new Offset(-scrollOffset, 0.0)
       )
     );
@@ -272,7 +358,7 @@
     this.paintOffset
   }) : super(key: key);
 
-  final EditableString value;
+  final InputValue value;
   final TextStyle style;
   final Color cursorColor;
   final bool showCursor;
diff --git a/packages/flutter/lib/src/widgets/enter_exit_transition.dart b/packages/flutter/lib/src/widgets/enter_exit_transition.dart
index c12aef5..a71d85b 100644
--- a/packages/flutter/lib/src/widgets/enter_exit_transition.dart
+++ b/packages/flutter/lib/src/widgets/enter_exit_transition.dart
@@ -4,8 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-
 import 'basic.dart';
 import 'framework.dart';
 
diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart
index 4e97db8..53e47e4 100644
--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -8,7 +8,7 @@
 import 'package:flutter/rendering.dart';
 
 export 'dart:ui' show hashValues, hashList;
-export 'package:flutter/rendering.dart' show debugPrint;
+export 'package:flutter/rendering.dart' show RenderObject, RenderBox, debugPrint;
 
 // KEYS
 
diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart
index 833b9a1..9b3b182 100644
--- a/packages/flutter/lib/src/widgets/heroes.dart
+++ b/packages/flutter/lib/src/widgets/heroes.dart
@@ -4,8 +4,6 @@
 
 import 'dart:collection';
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/scheduler.dart';
 
 import 'basic.dart';
diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart
index 94b7054..fb72162 100644
--- a/packages/flutter/lib/src/widgets/implicit_animations.dart
+++ b/packages/flutter/lib/src/widgets/implicit_animations.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
-
 import 'basic.dart';
 import 'framework.dart';
 
diff --git a/packages/flutter/lib/src/widgets/mimic.dart b/packages/flutter/lib/src/widgets/mimic.dart
index 0ae06a7..2260eee 100644
--- a/packages/flutter/lib/src/widgets/mimic.dart
+++ b/packages/flutter/lib/src/widgets/mimic.dart
@@ -4,8 +4,7 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
+import 'package:flutter/rendering.dart' show RenderStack;
 
 import 'basic.dart';
 import 'framework.dart';
@@ -110,7 +109,9 @@
 
     RenderBox stack = context.ancestorRenderObjectOfType(const TypeMatcher<RenderStack>());
     // TODO(abarth): Handle the case where the transform here isn't just a translation.
-    Point localPosition = stack == null ? globalPosition: stack.globalToLocal(globalPosition);
+    // TODO(ianh): We should probably be getting the overlay's render object rather than looking for a RenderStack.
+    assert(stack != null);
+    Point localPosition = stack.globalToLocal(globalPosition);
     return new Positioned(
       left: localPosition.x,
       top: localPosition.y,
diff --git a/packages/flutter/lib/src/widgets/mixed_viewport.dart b/packages/flutter/lib/src/widgets/mixed_viewport.dart
index fcac2af..b855d3a 100644
--- a/packages/flutter/lib/src/widgets/mixed_viewport.dart
+++ b/packages/flutter/lib/src/widgets/mixed_viewport.dart
@@ -103,7 +103,7 @@
 
   /// Returns false if any of the previously-cached offsets have been marked as
   /// invalid and need to be updated.
-  bool get isValid => _invalidIndices.length == 0;
+  bool get _isValid => _invalidIndices.isEmpty;
 
   /// The constraints for which the current offsets are valid.
   BoxConstraints _lastLayoutConstraints;
@@ -139,17 +139,20 @@
 
   void mount(Element parent, dynamic newSlot) {
     super.mount(parent, newSlot);
-    renderObject.callback = layout;
-    renderObject.totalExtentCallback = _noIntrinsicExtent;
-    renderObject.maxCrossAxisExtentCallback = _noIntrinsicExtent;
-    renderObject.minCrossAxisExtentCallback = _noIntrinsicExtent;
+    renderObject
+      ..direction = widget.direction
+      ..callback = layout
+      ..totalExtentCallback = _noIntrinsicExtent
+      ..maxCrossAxisExtentCallback = _noIntrinsicExtent
+      ..minCrossAxisExtentCallback = _noIntrinsicExtent;
   }
 
   void unmount() {
-    renderObject.callback = null;
-    renderObject.totalExtentCallback = null;
-    renderObject.minCrossAxisExtentCallback = null;
-    renderObject.maxCrossAxisExtentCallback = null;
+    renderObject
+      ..callback = null
+      ..totalExtentCallback = null
+      ..minCrossAxisExtentCallback = null
+      ..maxCrossAxisExtentCallback = null;
     super.unmount();
   }
 
@@ -167,14 +170,15 @@
     return null;
   }
 
-  static const Object _omit = const Object(); // used as a slot when it's not yet time to attach the child
+  static final Object _omit = new Object(); // used as a slot when it's not yet time to attach the child
 
   void update(MixedViewport newWidget) {
     _ChangeDescription changes = newWidget.evaluateChangesFrom(widget);
     super.update(newWidget);
+    renderObject.direction = widget.direction;
     if (changes == _ChangeDescription.resized)
       _resetCache();
-    if (changes != _ChangeDescription.none || !isValid) {
+    if (changes != _ChangeDescription.none || !_isValid) {
       renderObject.markNeedsLayout();
     } else {
       // We have to reinvoke our builders because they might return new data.
@@ -197,20 +201,20 @@
       assert(renderObject != null);
       final int startIndex = _firstVisibleChildIndex;
       int lastIndex = startIndex + _childrenByKey.length - 1;
-      Element nextSibling = null;
-      for (int index = lastIndex; index >= startIndex; index -= 1) {
+      Element previousChild = null;
+      for (int index = startIndex; index <= lastIndex; index += 1) {
         final Widget newWidget = _buildWidgetAt(index);
         final _ChildKey key = new _ChildKey.fromWidget(newWidget);
         final Element oldElement = _childrenByKey[key];
         assert(oldElement != null);
-        final Element newElement = updateChild(oldElement, newWidget, nextSibling);
+        final Element newElement = updateChild(oldElement, newWidget, previousChild);
         assert(newElement != null);
         _childrenByKey[key] = newElement;
         // Verify that it hasn't changed size.
         // If this assertion fires, it means you didn't call "invalidate"
         // before changing the size of one of your items.
         assert(_debugIsSameSize(newElement, index, _lastLayoutConstraints));
-        nextSibling = newElement;
+        previousChild = newElement;
       }
     }
   }
@@ -283,8 +287,7 @@
   Element _getElement(int index, BoxConstraints innerConstraints) {
     assert(index <= _childOffsets.length - 1);
     final Widget newWidget = _buildWidgetAt(index);
-    final Element newElement = _inflateOrUpdateWidget(newWidget);
-    return newElement;
+    return _inflateOrUpdateWidget(newWidget);
   }
 
   // Build the widget at index.
@@ -293,8 +296,7 @@
     final Widget newWidget = _maybeBuildWidgetAt(index);
     if (newWidget == null)
       return null;
-    final Element newElement = _inflateOrUpdateWidget(newWidget);
-    return newElement;
+    return _inflateOrUpdateWidget(newWidget);
   }
 
   // Build the widget at index, handling the case where there is no such widget.
@@ -349,39 +351,39 @@
     return result;
   }
 
+  double _getMaxExtent(BoxConstraints constraints) {
+    switch (widget.direction) {
+      case Axis.vertical:
+        assert(constraints.maxHeight < double.INFINITY &&
+          'There is no point putting a lazily-built vertical MixedViewport inside a box with infinite internal ' +
+          'height (e.g. inside something else that scrolls vertically), because it would then just eagerly build ' +
+          'all the children. You probably want to put the MixedViewport inside a Container with a fixed height.' is String);
+        return constraints.maxHeight;
+      case Axis.horizontal:
+        assert(constraints.maxWidth < double.INFINITY &&
+          'There is no point putting a lazily-built horizontal MixedViewport inside a box with infinite internal ' +
+          'width (e.g. inside something else that scrolls horizontally), because it would then just eagerly build ' +
+          'all the children. You probably want to put the MixedViewport inside a Container with a fixed width.' is String);
+        return constraints.maxWidth;
+    }
+  }
+
   /// This is the core lazy-build algorithm. It builds widgets incrementally
   /// from index 0 until it has built enough widgets to cover itself, and
   /// discards any widgets that are not displayed.
   void _doLayout(BoxConstraints constraints) {
-    Map<_ChildKey, Element> newChildren = new Map<_ChildKey, Element>();
-    Map<int, Element> builtChildren = new Map<int, Element>();
+    final Map<_ChildKey, Element> newChildren = new Map<_ChildKey, Element>();
+    final Map<int, Element> builtChildren = new Map<int, Element>();
 
     // Establish the start and end offsets based on our current constraints.
-    double extent;
-    switch (widget.direction) {
-      case Axis.vertical:
-        extent = constraints.maxHeight;
-        assert(extent < double.INFINITY &&
-          'There is no point putting a lazily-built vertical MixedViewport inside a box with infinite internal ' +
-          'height (e.g. inside something else that scrolls vertically), because it would then just eagerly build ' +
-          'all the children. You probably want to put the MixedViewport inside a Container with a fixed height.' is String);
-        break;
-      case Axis.horizontal:
-        extent = constraints.maxWidth;
-        assert(extent < double.INFINITY &&
-          'There is no point putting a lazily-built horizontal MixedViewport inside a box with infinite internal ' +
-          'width (e.g. inside something else that scrolls horizontally), because it would then just eagerly build ' +
-          'all the children. You probably want to put the MixedViewport inside a Container with a fixed width.' is String);
-        break;
-    }
-    final double endOffset = widget.startOffset + extent;
+    final double endOffset = widget.startOffset + _getMaxExtent(constraints);
 
     // Create the constraints that we will use to measure the children.
     final BoxConstraints innerConstraints = _getInnerConstraints(constraints);
 
     // Before doing the actual layout, fix the offsets for the widgets whose
     // size has apparently changed.
-    if (!isValid) {
+    if (!_isValid) {
       assert(_childOffsets.length > 0);
       assert(_childOffsets.length == _childExtents.length + 1);
       List<int> invalidIndices = _invalidIndices.toList();
@@ -512,13 +514,12 @@
     assert(!haveChildren || startIndex < _childExtents.length);
 
     // Build the other widgets that are visible.
-    int index = startIndex;
+    int index;
     if (haveChildren) {
       // Update the renderObject configuration
-      renderObject.direction = renderObject.direction;
-      renderObject.startOffset = _childOffsets[index] - widget.startOffset;
+      renderObject.startOffset = _childOffsets[startIndex] - widget.startOffset;
       // Build all the widgets we still need.
-      while (_childOffsets[index] < endOffset) {
+      for (index = startIndex; _childOffsets[index] < endOffset; index += 1) {
         if (!builtChildren.containsKey(index)) {
           Element element = _maybeGetElement(index, innerConstraints);
           if (element == null) {
@@ -543,7 +544,6 @@
           builtChildren[index] = element;
         }
         assert(builtChildren[index] != null);
-        index += 1;
       }
     }
 
@@ -554,6 +554,7 @@
     }
 
     if (haveChildren) {
+      assert(index != null);
       // Place all our children in our RenderObject.
       // All the children we are placing are in builtChildren and newChildren.
       Element previousChild = null;
diff --git a/packages/flutter/lib/src/widgets/modal_barrier.dart b/packages/flutter/lib/src/widgets/modal_barrier.dart
index b7e013b..942432d 100644
--- a/packages/flutter/lib/src/widgets/modal_barrier.dart
+++ b/packages/flutter/lib/src/widgets/modal_barrier.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
-
 import 'basic.dart';
 import 'framework.dart';
 import 'gesture_detector.dart';
diff --git a/packages/flutter/lib/src/widgets/pageable_list.dart b/packages/flutter/lib/src/widgets/pageable_list.dart
index e08c101..2386804 100644
--- a/packages/flutter/lib/src/widgets/pageable_list.dart
+++ b/packages/flutter/lib/src/widgets/pageable_list.dart
@@ -4,8 +4,7 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
+import 'package:flutter/rendering.dart' show RenderList, ViewportDimensions;
 
 import 'basic.dart';
 import 'framework.dart';
diff --git a/packages/flutter/lib/src/widgets/pages.dart b/packages/flutter/lib/src/widgets/pages.dart
index 92b78cb..edbe3bc 100644
--- a/packages/flutter/lib/src/widgets/pages.dart
+++ b/packages/flutter/lib/src/widgets/pages.dart
@@ -4,8 +4,7 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-
+import 'basic.dart';
 import 'navigator.dart';
 import 'overlay.dart';
 import 'routes.dart';
diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart
index 07fbc9f..09ea237 100644
--- a/packages/flutter/lib/src/widgets/routes.dart
+++ b/packages/flutter/lib/src/widgets/routes.dart
@@ -4,8 +4,6 @@
 
 import 'dart:async';
 
-import 'package:flutter/animation.dart';
-
 import 'basic.dart';
 import 'focus.dart';
 import 'framework.dart';
diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart
index 8036dc5..6a90b01 100644
--- a/packages/flutter/lib/src/widgets/scrollable.dart
+++ b/packages/flutter/lib/src/widgets/scrollable.dart
@@ -4,12 +4,11 @@
 
 import 'dart:async';
 import 'dart:math' as math;
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show window;
 
 import 'package:newton/newton.dart';
-import 'package:flutter/animation.dart';
 import 'package:flutter/gestures.dart';
-import 'package:flutter/rendering.dart';
+import 'package:flutter/rendering.dart' show HasScrollDirection;
 
 import 'basic.dart';
 import 'framework.dart';
diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart
index 0a81098..8545052 100644
--- a/packages/flutter/lib/src/widgets/semantics_debugger.dart
+++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart
@@ -3,9 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:math' as math;
-import 'dart:ui' as ui;
 
-import 'package:flutter/painting.dart';
 import 'package:flutter/rendering.dart';
 import 'package:sky_services/semantics/semantics.mojom.dart' as mojom;
 
@@ -193,17 +191,17 @@
       if (innerRect.isEmpty) {
         Paint fill = new Paint()
          ..color = lineColor
-         ..style = ui.PaintingStyle.fill;
+         ..style = PaintingStyle.fill;
         canvas.drawRect(rect, fill);
       } else {
         Paint fill = new Paint()
          ..color = const Color(0xFFFFFFFF)
-         ..style = ui.PaintingStyle.fill;
+         ..style = PaintingStyle.fill;
         canvas.drawRect(rect, fill);
         Paint line = new Paint()
          ..strokeWidth = rank * 2.0
          ..color = lineColor
-         ..style = ui.PaintingStyle.stroke;
+         ..style = PaintingStyle.stroke;
         canvas.drawRect(innerRect, line);
       }
       if (textPainter != null) {
diff --git a/packages/flutter/lib/src/widgets/status_transitions.dart b/packages/flutter/lib/src/widgets/status_transitions.dart
index f118d3b..a3a0bc5 100644
--- a/packages/flutter/lib/src/widgets/status_transitions.dart
+++ b/packages/flutter/lib/src/widgets/status_transitions.dart
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/animation.dart';
-
+import 'basic.dart';
 import 'framework.dart';
 
 /// A component that rebuilds when the given animation changes status.
diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart
index a0cee01..ffeb756 100644
--- a/packages/flutter/lib/src/widgets/transitions.dart
+++ b/packages/flutter/lib/src/widgets/transitions.dart
@@ -4,8 +4,6 @@
 
 import 'dart:math' as math;
 
-import 'package:flutter/animation.dart';
-import 'package:flutter/rendering.dart';
 import 'package:vector_math/vector_math_64.dart' show Matrix4;
 
 import 'basic.dart';
diff --git a/packages/flutter/test/engine/canvas_test_disabled.dart b/packages/flutter/test/engine/canvas_test_disabled.dart
index e6db08e..2674118 100644
--- a/packages/flutter/test/engine/canvas_test_disabled.dart
+++ b/packages/flutter/test/engine/canvas_test_disabled.dart
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
-import 'dart:ui' show Rect, Color, Paint;
+import 'dart:ui' as ui show PictureRecorder;
+import 'dart:ui' show Rect, Color, Paint, Canvas;
 
 import 'package:test/test.dart';
 import 'package:vector_math/vector_math_64.dart';
@@ -11,7 +11,7 @@
 void main() {
 
   ui.PictureRecorder recorder = new ui.PictureRecorder();
-  ui.Canvas canvas = new ui.Canvas(recorder, new Rect.fromLTRB(0.0, 0.0, 100.0, 100.0));
+  Canvas canvas = new Canvas(recorder, new Rect.fromLTRB(0.0, 0.0, 100.0, 100.0));
 
   test("matrix access should work", () {
     // Matrix equality doesn't work!
diff --git a/packages/flutter/test/rendering/image_test.dart b/packages/flutter/test/rendering/image_test.dart
index 7e36964..264d60d 100644
--- a/packages/flutter/test/rendering/image_test.dart
+++ b/packages/flutter/test/rendering/image_test.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image;
 
 import 'package:flutter/rendering.dart';
 import 'package:test/test.dart';
diff --git a/packages/flutter/test/widget/draggable_test.dart b/packages/flutter/test/widget/draggable_test.dart
index 8314617..e8cb088 100644
--- a/packages/flutter/test/widget/draggable_test.dart
+++ b/packages/flutter/test/widget/draggable_test.dart
@@ -168,7 +168,68 @@
       tester.pump();
       expect(events, equals(<String>['tap', 'tap', 'drop']));
       events.clear();
+    });
+
+    testWidgets((WidgetTester tester) {
+      TestPointer pointer = new TestPointer(7);
+
+      List<String> events = <String>[];
+      Point firstLocation, secondLocation;
+
+      tester.pumpWidget(new MaterialApp(
+        routes: <String, RouteBuilder>{
+          '/': (RouteArguments args) { return new Column(
+            children: <Widget>[
+              new Draggable(
+                data: 1,
+                child: new GestureDetector(
+                  behavior: HitTestBehavior.opaque,
+                  onTap: () {
+                    events.add('tap');
+                  },
+                  child: new Container(
+                    child: new Text('Button')
+                  )
+                ),
+                feedback: new Text('Dragging')
+              ),
+              new DragTarget(
+                builder: (context, data, rejects) {
+                  return new Text('Target');
+                },
+                onAccept: (data) {
+                  events.add('drop');
+                }
+              ),
+            ]);
+          },
+        }
+      ));
+
+      expect(events, isEmpty);
+      expect(tester.findText('Button'), isNotNull);
+      expect(tester.findText('Target'), isNotNull);
+
+      expect(events, isEmpty);
+      tester.tap(tester.findText('Button'));
+      expect(events, equals(<String>['tap']));
+      events.clear();
+
+      firstLocation = tester.getCenter(tester.findText('Button'));
+      tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
+      tester.pump();
+
+      secondLocation = tester.getCenter(tester.findText('Target'));
+      tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
+      tester.pump();
+
+      expect(events, isEmpty);
+      tester.dispatchEvent(pointer.up(), firstLocation);
+      tester.pump();
+      expect(events, equals(<String>['drop']));
+      events.clear();
 
     });
+
   });
 }
diff --git a/packages/flutter/test/widget/input_test.dart b/packages/flutter/test/widget/input_test.dart
index ed3248e..6e57628 100644
--- a/packages/flutter/test/widget/input_test.dart
+++ b/packages/flutter/test/widget/input_test.dart
@@ -30,15 +30,16 @@
   test('Editable text has consistent size', () {
     testWidgets((WidgetTester tester) {
       GlobalKey inputKey = new GlobalKey();
-      String inputValue;
+      InputValue inputValue = InputValue.empty;
 
       Widget builder() {
         return new Center(
           child: new Material(
             child: new Input(
+              value: inputValue,
               key: inputKey,
               hintText: 'Placeholder',
-              onChanged: (String value) { inputValue = value; }
+              onChanged: (InputValue value) { inputValue = value; }
             )
           )
         );
@@ -58,7 +59,7 @@
           ..composingExtent = testValue.length);
 
         // Check that the onChanged event handler fired.
-        expect(inputValue, equals(testValue));
+        expect(inputValue.text, equals(testValue));
 
         tester.pumpWidget(builder());
       }
@@ -88,7 +89,7 @@
 
       tester.pumpWidget(builder());
 
-      RawEditableTextState editableText = tester.findStateOfType(RawEditableTextState);
+      RawInputLineState editableText = tester.findStateOfType(RawInputLineState);
 
       // Check that the cursor visibility toggles after each blink interval.
       void checkCursorToggle() {
diff --git a/packages/flutter/test/widget/mixed_viewport_test.dart b/packages/flutter/test/widget/mixed_viewport_test.dart
index 24dca23..770e2bf 100644
--- a/packages/flutter/test/widget/mixed_viewport_test.dart
+++ b/packages/flutter/test/widget/mixed_viewport_test.dart
@@ -150,4 +150,50 @@
       callbackTracker.clear();
     });
   });
+
+  test('MixedViewport reinvoke builders', () {
+    testWidgets((WidgetTester tester) {
+      List<int> callbackTracker = <int>[];
+      List<String> text = <String>[];
+
+      IndexedBuilder itemBuilder = (BuildContext context, int i) {
+        callbackTracker.add(i);
+        return new Container(
+          key: new ValueKey<int>(i),
+          width: 500.0, // this should be ignored
+          height: 220.0,
+          child: new Text("$i")
+        );
+      };
+
+      ElementVisitor collectText = (Element element) {
+        final Widget widget = element.widget;
+        if (widget is Text)
+          text.add(widget.data);
+      };
+
+      Widget builder() {
+        return new MixedViewport(
+          builder: itemBuilder,
+          startOffset: 0.0
+        );
+      }
+
+      tester.pumpWidget(builder());
+
+      expect(callbackTracker, equals([0, 1, 2]));
+      callbackTracker.clear();
+      tester.walkElements(collectText);
+      expect(text, equals(['0', '1', '2']));
+      text.clear();
+
+      tester.pumpWidget(builder());
+
+      expect(callbackTracker, equals([0, 1, 2]));
+      callbackTracker.clear();
+      tester.walkElements(collectText);
+      expect(text, equals(['0', '1', '2']));
+      text.clear();
+    });
+  });
 }
diff --git a/packages/flutter/test/widget/page_forward_transitions_test.dart b/packages/flutter/test/widget/page_forward_transitions_test.dart
index 8471d1b..98e7a38 100644
--- a/packages/flutter/test/widget/page_forward_transitions_test.dart
+++ b/packages/flutter/test/widget/page_forward_transitions_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter/animation.dart';
 import 'package:flutter/material.dart';
 import 'package:test/test.dart' hide TypeMatcher;
 
diff --git a/packages/flutter/test/widget/positioned_test.dart b/packages/flutter/test/widget/positioned_test.dart
index 28f2c71..7a03b2c 100644
--- a/packages/flutter/test/widget/positioned_test.dart
+++ b/packages/flutter/test/widget/positioned_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter/animation.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 import 'package:test/test.dart';
diff --git a/packages/flutter/test/widget/shader_mask_test.dart b/packages/flutter/test/widget/shader_mask_test.dart
index 513f577..72a1df7 100644
--- a/packages/flutter/test/widget/shader_mask_test.dart
+++ b/packages/flutter/test/widget/shader_mask_test.dart
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' show Shader;
 
 import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter/painting.dart';
 import 'package:flutter/widgets.dart';
 import 'package:test/test.dart';
 
-ui.Shader createShader(Rect bounds) {
+Shader createShader(Rect bounds) {
   return new LinearGradient(
       begin: bounds.topLeft,
       end: bounds.bottomLeft,
diff --git a/packages/flutter_sprites/lib/flutter_sprites.dart b/packages/flutter_sprites/lib/flutter_sprites.dart
index 6d14e81..a660157 100644
--- a/packages/flutter_sprites/lib/flutter_sprites.dart
+++ b/packages/flutter_sprites/lib/flutter_sprites.dart
@@ -10,12 +10,10 @@
 import 'dart:convert';
 import 'dart:math' as math;
 import 'dart:typed_data';
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show Image;
 
 import 'package:box2d/box2d.dart' as box2d;
-import 'package:flutter/animation.dart';
 import 'package:flutter/gestures.dart';
-import 'package:flutter/painting.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/scheduler.dart';
 import 'package:flutter/services.dart';
diff --git a/packages/flutter_sprites/lib/src/effect_line.dart b/packages/flutter_sprites/lib/src/effect_line.dart
index 05ca8e8..9af9050 100644
--- a/packages/flutter_sprites/lib/src/effect_line.dart
+++ b/packages/flutter_sprites/lib/src/effect_line.dart
@@ -15,7 +15,7 @@
 
   EffectLine({
     this.texture: null,
-    this.transferMode: ui.TransferMode.dstOver,
+    this.transferMode: TransferMode.dstOver,
     List<Point> points,
     this.widthMode : EffectLineWidthMode.linear,
     this.minWidth: 10.0,
@@ -38,8 +38,8 @@
     _colorSequence = colorSequence;
     if (_colorSequence == null) {
       _colorSequence = new ColorSequence.fromStartAndEndColor(
-        new Color(0xffffffff),
-        new Color(0xffffffff)
+        const Color(0xffffffff),
+        const Color(0xffffffff)
       );
     }
 
@@ -51,7 +51,7 @@
 
   final Texture texture;
 
-  final ui.TransferMode transferMode;
+  final TransferMode transferMode;
 
   final EffectLineWidthMode widthMode;
   final double minWidth;
diff --git a/packages/flutter_sprites/lib/src/layer.dart b/packages/flutter_sprites/lib/src/layer.dart
index 7a8e084..8c8e592 100644
--- a/packages/flutter_sprites/lib/src/layer.dart
+++ b/packages/flutter_sprites/lib/src/layer.dart
@@ -22,7 +22,7 @@
   Layer([this.layerRect = null]);
 
   Paint _cachedPaint = new Paint()
-    ..filterQuality = ui.FilterQuality.low
+    ..filterQuality = FilterQuality.low
     ..isAntiAlias = false;
 
   void _prePaint(Canvas canvas, Matrix4 matrix) {
diff --git a/packages/flutter_sprites/lib/src/particle_system.dart b/packages/flutter_sprites/lib/src/particle_system.dart
index 90dd254..ee40e7f 100644
--- a/packages/flutter_sprites/lib/src/particle_system.dart
+++ b/packages/flutter_sprites/lib/src/particle_system.dart
@@ -144,7 +144,7 @@
 
   /// The transfer mode used to draw the particle system. Default is
   /// [TransferMode.plus].
-  ui.TransferMode transferMode;
+  TransferMode transferMode;
 
   List<_Particle> _particles;
 
@@ -154,7 +154,7 @@
   double opacity = 1.0;
 
   static Paint _paint = new Paint()
-    ..filterQuality = ui.FilterQuality.low
+    ..filterQuality = FilterQuality.low
     ..isAntiAlias = false;
 
   ParticleSystem(this.texture,
@@ -186,7 +186,7 @@
                   this.redVar: 0,
                   this.greenVar: 0,
                   this.blueVar: 0,
-                  this.transferMode: ui.TransferMode.plus,
+                  this.transferMode: TransferMode.plus,
                   this.numParticlesToEmit: 0,
                   this.autoRemoveOnFinish: true}) {
     _particles = new List<_Particle>();
@@ -362,7 +362,7 @@
   void paint(Canvas canvas) {
     if (opacity == 0.0) return;
 
-    List<ui.RSTransform> transforms = <ui.RSTransform>[];
+    List<RSTransform> transforms = <RSTransform>[];
     List<Rect> rects = <Rect>[];
     List<Color> colors = <Color>[];
 
@@ -391,7 +391,7 @@
       double ay = rect.height / 2;
       double tx = particle.pos[0] + -scos * ax + ssin * ay;
       double ty = particle.pos[1] + -ssin * ax - scos * ay;
-      ui.RSTransform transform = new ui.RSTransform(scos, ssin, tx, ty);
+      RSTransform transform = new RSTransform(scos, ssin, tx, ty);
       transforms.add(transform);
 
       // Color
@@ -417,7 +417,7 @@
     }
 
     canvas.drawAtlas(texture.image, transforms, rects, colors,
-      ui.TransferMode.modulate, null, _paint);
+      TransferMode.modulate, null, _paint);
   }
 }
 
diff --git a/packages/flutter_sprites/lib/src/physics_debug.dart b/packages/flutter_sprites/lib/src/physics_debug.dart
index bdba48e..2461639 100644
--- a/packages/flutter_sprites/lib/src/physics_debug.dart
+++ b/packages/flutter_sprites/lib/src/physics_debug.dart
@@ -43,7 +43,7 @@
   void drawCircle(Vector2 center, num radius, box2d.Color3i color, [Vector2 axis]) {
     Paint paint = new Paint()
       ..color = _toColor(color)
-      ..style = ui.PaintingStyle.stroke
+      ..style = PaintingStyle.stroke
       ..strokeWidth = 1.0;
 
     canvas.drawCircle(_toPoint(center), _scale(radius), paint);
diff --git a/packages/flutter_sprites/lib/src/sprite.dart b/packages/flutter_sprites/lib/src/sprite.dart
index 4b14073b..b770b9d 100644
--- a/packages/flutter_sprites/lib/src/sprite.dart
+++ b/packages/flutter_sprites/lib/src/sprite.dart
@@ -17,7 +17,7 @@
   bool constrainProportions = false;
 
   Paint _cachedPaint = new Paint()
-    ..filterQuality = ui.FilterQuality.low
+    ..filterQuality = FilterQuality.low
     ..isAntiAlias = false;
 
   /// Creates a new sprite from the provided [texture].
@@ -107,13 +107,13 @@
   ///
   ///     // Add the colors of the sprite with the colors of the background
   ///     mySprite.transferMode = TransferMode.plusMode;
-  ui.TransferMode transferMode;
+  TransferMode transferMode;
 
   void _updatePaint(Paint paint) {
     paint.color = new Color.fromARGB((255.0*_opacity).toInt(), 255, 255, 255);
 
     if (colorOverlay != null) {
-      paint.colorFilter = new ColorFilter.mode(colorOverlay, ui.TransferMode.srcATop);
+      paint.colorFilter = new ColorFilter.mode(colorOverlay, TransferMode.srcATop);
     }
 
     if (transferMode != null) {
diff --git a/packages/flutter_sprites/lib/src/textured_line.dart b/packages/flutter_sprites/lib/src/textured_line.dart
index 41def98..2cbe95f 100644
--- a/packages/flutter_sprites/lib/src/textured_line.dart
+++ b/packages/flutter_sprites/lib/src/textured_line.dart
@@ -38,8 +38,8 @@
       _cachedPaint = new Paint();
     } else {
       Matrix4 matrix = new Matrix4.identity();
-      ui.ImageShader shader = new ui.ImageShader(texture.image,
-        ui.TileMode.repeated, ui.TileMode.repeated, matrix.storage);
+      ImageShader shader = new ImageShader(texture.image,
+        TileMode.repeated, TileMode.repeated, matrix.storage);
 
       _cachedPaint = new Paint()
         ..shader = shader;
@@ -77,7 +77,7 @@
 
   bool removeArtifacts = true;
 
-  ui.TransferMode transferMode = ui.TransferMode.srcOver;
+  TransferMode transferMode = TransferMode.srcOver;
 
   Paint _cachedPaint = new Paint();
 
@@ -169,7 +169,7 @@
       lastMiter = currentMiter;
     }
 
-    canvas.drawVertices(ui.VertexMode.triangles, vertices, textureCoordinates, verticeColors, ui.TransferMode.modulate, indicies, _cachedPaint);
+    canvas.drawVertices(VertexMode.triangles, vertices, textureCoordinates, verticeColors, TransferMode.modulate, indicies, _cachedPaint);
   }
 
   double _xPosForStop(double stop) {
diff --git a/packages/flutter_sprites/lib/src/virtual_joystick.dart b/packages/flutter_sprites/lib/src/virtual_joystick.dart
index c660cf0..a9cbc97 100644
--- a/packages/flutter_sprites/lib/src/virtual_joystick.dart
+++ b/packages/flutter_sprites/lib/src/virtual_joystick.dart
@@ -14,7 +14,7 @@
     _paintControl = new Paint()
       ..color=new Color(0xffffffff)
       ..strokeWidth = 1.0
-      ..style = ui.PaintingStyle.stroke;
+      ..style = PaintingStyle.stroke;
   }
 
   Point _value = Point.origin;
diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart
index ec948d0..6c120f1 100644
--- a/packages/flutter_test/lib/src/widget_tester.dart
+++ b/packages/flutter_test/lib/src/widget_tester.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' as ui;
+import 'dart:ui' as ui show window;
 
 import 'package:quiver/testing/async.dart';
 import 'package:quiver/time.dart';
@@ -35,7 +35,7 @@
   }
 
   void setLocale(String languageCode, String countryCode) {
-    ui.Locale locale = new ui.Locale(languageCode, countryCode);
+    Locale locale = new Locale(languageCode, countryCode);
     binding.dispatchLocaleChanged(locale);
     async.flushMicrotasks();
   }
diff --git a/packages/flutter_tools/lib/src/commands/run_mojo.dart b/packages/flutter_tools/lib/src/commands/run_mojo.dart
index 77dc2a1..575acec 100644
--- a/packages/flutter_tools/lib/src/commands/run_mojo.dart
+++ b/packages/flutter_tools/lib/src/commands/run_mojo.dart
@@ -103,7 +103,7 @@
       args.add('--android');
       final String appName = path.basename(appPath);
       final String appDir = path.dirname(appPath);
-      args.add('http://app/$appName');
+      args.add('mojo:launcher http://app/$appName');
       args.add('--map-origin=http://app/=$appDir');
 
       final String flutterName = path.basename(flutterPath);
@@ -111,7 +111,7 @@
       args.add('--map-origin=http://flutter/=$flutterDir');
       args.add('--url-mappings=mojo:flutter=http://flutter/$flutterName');
     } else {
-      args.add('file://$appPath');
+      args.add('mojo:launcher file://$appPath');
       args.add('--url-mappings=mojo:flutter=file://$flutterPath');
     }
 
diff --git a/packages/flutter_tools/lib/src/commands/start.dart b/packages/flutter_tools/lib/src/commands/start.dart
index 9b9259e..62fd1d0 100644
--- a/packages/flutter_tools/lib/src/commands/start.dart
+++ b/packages/flutter_tools/lib/src/commands/start.dart
@@ -190,6 +190,13 @@
       printError('Error starting application on ${device.name}.');
     } else {
       startedSomething = true;
+
+      // If the user specified --start-paused (and the device supports it) then
+      // wait for the observatory port to become available before returning from
+      // `startApp()`.
+      if (startPaused && device.supportsStartPaused) {
+        await _delayUntilObservatoryAvailable('localhost', debugPort);
+      }
     }
   }
 
@@ -204,6 +211,34 @@
   return startedSomething ? 0 : 2;
 }
 
+/// Delay until the Observatory / service protocol is available.
+///
+/// This does not fail if we're unable to connect, and times out after the given
+/// [timeout].
+Future _delayUntilObservatoryAvailable(String host, int port, {
+  Duration timeout: const Duration(seconds: 10)
+}) async {
+  Stopwatch stopwatch = new Stopwatch()..start();
+
+  final String url = 'ws://$host:$port/ws';
+  printTrace('Looking for the observatory at $url.');
+
+  while (stopwatch.elapsed <= timeout) {
+    try {
+      WebSocket ws = await WebSocket.connect(url);
+
+      printTrace('Connected to the observatory port (${stopwatch.elapsedMilliseconds}ms).');
+      ws.close().catchError((error) => null);
+
+      return;
+    } catch (error) {
+      await new Future.delayed(new Duration(milliseconds: 250));
+    }
+  }
+
+  printTrace('Unable to connect to the observatory.');
+}
+
 /// Return a relative path if [fullPath] is contained by the cwd, else return an
 /// absolute path.
 String _getDisplayPath(String fullPath) {
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 7c865b3..274d1ff 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -98,6 +98,8 @@
 
   String get name;
 
+  bool get supportsStartPaused => true;
+
   /// Install an app package on the current device
   bool installApp(ApplicationPackage app);
 
diff --git a/packages/flutter_tools/lib/src/ios/device_ios.dart b/packages/flutter_tools/lib/src/ios/device_ios.dart
index a9c99a0..db509f8 100644
--- a/packages/flutter_tools/lib/src/ios/device_ios.dart
+++ b/packages/flutter_tools/lib/src/ios/device_ios.dart
@@ -82,6 +82,8 @@
 
   final String name;
 
+  bool get supportsStartPaused => false;
+
   static List<IOSDevice> getAttachedDevices([IOSDevice mockIOS]) {
     List<IOSDevice> devices = [];
     for (String id in _getAttachedDeviceIDs(mockIOS)) {
diff --git a/packages/playfair/lib/playfair.dart b/packages/playfair/lib/playfair.dart
index be292be..30a7e99 100644
--- a/packages/playfair/lib/playfair.dart
+++ b/packages/playfair/lib/playfair.dart
@@ -5,11 +5,4 @@
 /// A simple charting library for Flutter.
 library playfair;
 
-import 'dart:ui' as ui;
-import 'dart:math' as math;
-
-import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
-import 'package:flutter/painting.dart';
-
-part 'src/base.dart';
+export 'src/base.dart';
diff --git a/packages/playfair/lib/src/base.dart b/packages/playfair/lib/src/base.dart
index b1e985d..e69edce 100644
--- a/packages/playfair/lib/src/base.dart
+++ b/packages/playfair/lib/src/base.dart
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-part of playfair;
+import 'dart:math' as math;
+
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
 
 class ChartData {
   const ChartData({
@@ -54,17 +57,17 @@
   final TextTheme textTheme;
   final ChartData data;
 
-  RenderChart createRenderObject() => new RenderChart(textTheme: textTheme, data: data);
+  _RenderChart createRenderObject() => new _RenderChart(textTheme: textTheme, data: data);
 
-  void updateRenderObject(RenderChart renderObject, _ChartWrapper oldWidget) {
-    renderObject.textTheme = textTheme;
-    renderObject.data = data;
+  void updateRenderObject(_RenderChart renderObject, _ChartWrapper oldWidget) {
+    renderObject
+      ..textTheme = textTheme
+      ..data = data;
   }
 }
 
-class RenderChart extends RenderConstrainedBox {
-
-  RenderChart({
+class _RenderChart extends RenderConstrainedBox {
+  _RenderChart({
     TextTheme textTheme,
     ChartData data
   }) : _painter = new ChartPainter(textTheme: textTheme, data: data),
@@ -98,7 +101,7 @@
   }
 }
 
-class Gridline {
+class _Gridline {
   double value;
   TextPainter labelPainter;
   Point labelPosition;
@@ -106,7 +109,7 @@
   Point end;
 }
 
-class Indicator {
+class _Indicator {
   Point start;
   Point end;
   TextPainter labelPainter;
@@ -148,18 +151,18 @@
   Rect _rect;
 
   // These are updated by _layout()
-  List<Gridline> _horizontalGridlines;
+  List<_Gridline> _horizontalGridlines;
   List<Point> _markers;
-  Indicator _indicator;
+  _Indicator _indicator;
 
   void _layout() {
     // Create the scale labels
     double yScaleWidth = 0.0;
-    _horizontalGridlines = new List<Gridline>();
+    _horizontalGridlines = new List<_Gridline>();
     assert(data.numHorizontalGridlines > 1);
     double stepSize = (data.endY - data.startY) / (data.numHorizontalGridlines - 1);
     for(int i = 0; i < data.numHorizontalGridlines; i++) {
-      Gridline gridline = new Gridline()
+      _Gridline gridline = new _Gridline()
         ..value = _roundToPlaces(data.startY + stepSize * i, data.roundToPlaces);
       if (gridline.value < data.startY || gridline.value > data.endY)
         continue;  // TODO(jackson): Align things so this doesn't ever happen
@@ -185,7 +188,7 @@
     );
 
     // Left align and vertically center the labels on the right side
-    for(Gridline gridline in _horizontalGridlines) {
+    for(_Gridline gridline in _horizontalGridlines) {
       gridline.start = _convertPointToRectSpace(new Point(data.startX, gridline.value), markerRect);
       gridline.end = _convertPointToRectSpace(new Point(data.endX, gridline.value), markerRect);
       gridline.labelPosition = new Point(
@@ -206,13 +209,13 @@
     if (data.indicatorLine != null &&
         data.indicatorLine >= data.startY &&
         data.indicatorLine <= data.endY) {
-      _indicator = new Indicator()
+      _indicator = new _Indicator()
         ..start = _convertPointToRectSpace(new Point(data.startX, data.indicatorLine), markerRect)
         ..end = _convertPointToRectSpace(new Point(data.endX, data.indicatorLine), markerRect);
       if (data.indicatorText != null) {
         TextSpan text = new StyledTextSpan(
           _textTheme.body1,
-          [new PlainTextSpan("${data.indicatorText}")]
+          <TextSpan>[new PlainTextSpan("${data.indicatorText}")]
         );
         _indicator.labelPainter = new TextPainter(text)
           ..maxWidth = markerRect.width
@@ -236,17 +239,17 @@
     return new Point(x, y);
   }
 
-  void _paintGrid(ui.Canvas canvas) {
+  void _paintGrid(Canvas canvas) {
     Paint paint = new Paint()
       ..strokeWidth = kGridStrokeWidth
       ..color = kGridColor;
-    for(Gridline gridline in _horizontalGridlines) {
+    for(_Gridline gridline in _horizontalGridlines) {
       gridline.labelPainter.paint(canvas, gridline.labelPosition.toOffset());
       canvas.drawLine(gridline.start, gridline.end, paint);
     }
   }
 
-  void _paintChart(ui.Canvas canvas) {
+  void _paintChart(Canvas canvas) {
     Paint paint = new Paint()
       ..strokeWidth = kMarkerStrokeWidth
       ..color = kMarkerColor;
@@ -256,11 +259,11 @@
       canvas.drawCircle(marker, kMarkerRadius, paint);
       path.lineTo(marker.x, marker.y);
     }
-    paint.style = ui.PaintingStyle.stroke;
+    paint.style = PaintingStyle.stroke;
     canvas.drawPath(path, paint);
   }
 
-  void _paintIndicator(ui.Canvas canvas) {
+  void _paintIndicator(Canvas canvas) {
     if (_indicator == null)
       return;
     Paint paint = new Paint()
@@ -271,7 +274,7 @@
       _indicator.labelPainter.paint(canvas, _indicator.labelPosition.toOffset());
   }
 
-  void paint(ui.Canvas canvas, Rect rect) {
+  void paint(Canvas canvas, Rect rect) {
     if (rect != _rect)
       _needsLayout = true;
     _rect = rect;