Revert "Implements the navigator page api (#50362)" (#53610)

This reverts commit 9a6eb7def3e932bc54f554200ec1fe7cdf2e630e.
diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart
index b57d352..c81cae0 100644
--- a/packages/flutter/lib/src/widgets/navigator.dart
+++ b/packages/flutter/lib/src/widgets/navigator.dart
@@ -36,11 +36,6 @@
 ///  * [Navigator], which is where all the [Route]s end up.
 typedef RouteFactory = Route<dynamic> Function(RouteSettings settings);
 
-/// Creates a route for the given context and route settings.
-///
-/// Used by [CustomBuilderPage.routeBuilder].
-typedef RouteBuilder<T> = Route<T> Function(BuildContext context, RouteSettings settings);
-
 /// Creates a series of one or more routes.
 ///
 /// Used by [Navigator.onGenerateInitialRoutes].
@@ -55,15 +50,6 @@
 /// [ModalRoute.removeScopedWillPopCallback], and [WillPopScope].
 typedef WillPopCallback = Future<bool> Function();
 
-/// Signature for the [Navigator.onPopPage] callback.
-///
-/// This callback must call [Route.didPop] on the specified route and must
-/// properly update the pages list the next time it is passed into
-/// [Navigator.pages] so that it no longer includes the corresponding [Page].
-/// (Otherwise, the page will be interpreted as a new page to show when the
-/// [Navigator.pages] list is next updated.)
-typedef PopPageCallback = bool Function(Route<dynamic> route, dynamic result);
-
 /// Indicates whether the current route should be popped.
 ///
 /// Used as the return value for [Route.willPop].
@@ -104,13 +90,6 @@
 /// See [MaterialPageRoute] for a route that replaces the entire screen with a
 /// platform-adaptive transition.
 ///
-/// A route can belong to a page if the [settings] are a subclass of [Page]. A
-/// page-based route, as opposite to pageless route, is created from
-/// [Page.createRoute] during [Navigator.pages] updates. The page associated
-/// with this route may change during the lifetime of the route. If the
-/// [Navigator] updates the page of this route, it calls [changedInternalState]
-/// to notify the route that the page has been updated.
-///
 /// The type argument `T` is the route's return type, as used by
 /// [currentResult], [popped], and [didPop]. The type `void` may be used if the
 /// route does not return a value.
@@ -119,7 +98,7 @@
   ///
   /// If the [settings] are not provided, an empty [RouteSettings] object is
   /// used instead.
-  Route({ RouteSettings settings }) : _settings = settings ?? const RouteSettings();
+  Route({ RouteSettings settings }) : settings = settings ?? const RouteSettings();
 
   /// The navigator that the route is in, if any.
   NavigatorState get navigator => _navigator;
@@ -128,26 +107,7 @@
   /// The settings for this route.
   ///
   /// See [RouteSettings] for details.
-  ///
-  /// The settings can change during the route's lifetime. If the settings
-  /// change, the route's overlays will be marked dirty (see
-  /// [changedInternalState]).
-  ///
-  /// If the route is created from a [Page] in the [Navigator.pages] list, then
-  /// this will be a [Page] subclass, and it will be updated each time its
-  /// corresponding [Page] in the [Navigator.pages] has changed. Once the
-  /// [Route] is removed from the history, this value stops updating (and
-  /// remains with its last value).
-  RouteSettings get settings => _settings;
-  RouteSettings _settings;
-
-  void _updateSettings(RouteSettings newSettings) {
-    assert(newSettings != null);
-    if (_settings != newSettings) {
-      _settings = newSettings;
-      changedInternalState();
-    }
-  }
+  final RouteSettings settings;
 
   /// The overlay entries of this route.
   ///
@@ -287,6 +247,7 @@
   ///
   /// See [popped], [didComplete], and [currentResult] for a discussion of the
   /// `result` argument.
+  @protected
   @mustCallSuper
   bool didPop(T result) {
     didComplete(result);
@@ -486,82 +447,6 @@
   String toString() => '${objectRuntimeType(this, 'RouteSettings')}("$name", $arguments)';
 }
 
-/// Describes the configuration of a [Route].
-///
-/// The type argument `T` is the corresponding [Route]'s return type, as
-/// used by [Route.currentResult], [Route.popped], and [Route.didPop].
-///
-/// See also:
-///
-///  * [Navigator.pages], which accepts a list of [Page]s and updates its routes
-///    history.
-///  * [CustomBuilderPage], a [Page] subclass that provides the API to build a
-///    customized route.
-abstract class Page<T> extends RouteSettings {
-  /// Creates a page and initializes [key] for subclasses.
-  ///
-  /// The [arguments] argument must not be null.
-  const Page({
-    this.key,
-    String name,
-    Object arguments,
-  }) : super(name: name, arguments: arguments);
-
-  /// The key associated with this page.
-  ///
-  /// This key will be used for comparing pages in [canUpdate].
-  final LocalKey key;
-
-  /// Whether this page can be updated with the [other] page.
-  ///
-  /// Two pages are consider updatable if they have same the [runtimeType] and
-  /// [key].
-  bool canUpdate(Page<dynamic> other) {
-    return other.runtimeType == runtimeType &&
-           other.key == key;
-  }
-
-  /// Creates the [Route] that corresponds to this page.
-  ///
-  /// The created [Route] must have its [Route.settings] property set to this [Page].
-  Route<T> createRoute(BuildContext context);
-
-  @override
-  String toString() => '${objectRuntimeType(this, 'Page')}("$name", $key, $arguments)';
-}
-
-/// A [Page] that builds a customized [Route] based on the [routeBuilder].
-///
-/// The type argument `T` is the corresponding [Route]'s return type, as
-/// used by [Route.currentResult], [Route.popped], and [Route.didPop].
-class CustomBuilderPage<T> extends Page<T> {
-  /// Creates a page with a custom route builder.
-  ///
-  /// Use [routeBuilder] to specify the route that will be created from this
-  /// page.
-  const CustomBuilderPage({
-    @required LocalKey key,
-    @required this.routeBuilder,
-    String name,
-    Object arguments,
-  }) : assert(key != null),
-       assert(routeBuilder != null),
-       super(key: key, name: name, arguments: arguments);
-
-  /// A builder that will be called during [createRoute] to create a [Route].
-  ///
-  /// The routes returned from this builder must have their settings equal to
-  /// the input `settings`.
-  final RouteBuilder<T> routeBuilder;
-
-  @override
-  Route<T> createRoute(BuildContext context) {
-    final Route<T> route = routeBuilder(context, this);
-    assert(route.settings == this);
-    return route;
-  }
-}
-
 /// An interface for observing the behavior of a [Navigator].
 class NavigatorObserver {
   /// The navigator that the observer is observing, if any.
@@ -606,336 +491,6 @@
   void didStopUserGesture() { }
 }
 
-/// A [Route] wrapper interface that can be staged for [TransitionDelegate] to
-/// decide how its underlying [Route] should transition on or off screen.
-abstract class RouteTransitionRecord {
-  /// Retrieves the wrapped [Route].
-  Route<dynamic> get route;
-
-  /// Whether this route is entering the screen.
-  ///
-  /// If this property is true, this route requires an explicit decision on how
-  /// to transition into the screen. Such a decision should be made in the
-  /// [TransitionDelegate.resolve].
-  bool get isEntering;
-
-  bool _debugWaitingForExitDecision = false;
-
-  /// Marks the [route] to be pushed with transition.
-  ///
-  /// During [TransitionDelegate.resolve], this can be called on an entering
-  /// route (where [RouteTransitionRecord.isEntering] is true) in indicate that the
-  /// route should be pushed onto the [Navigator] with an animated transition.
-  void markForPush();
-
-  /// Marks the [route] to be added without transition.
-  ///
-  /// During [TransitionDelegate.resolve], this can be called on an entering
-  /// route (where [RouteTransitionRecord.isEntering] is true) in indicate that the
-  /// route should be added onto the [Navigator] without an animated transition.
-  void markForAdd();
-
-  /// Marks the [route] to be popped with transition.
-  ///
-  /// During [TransitionDelegate.resolve], this can be called on an exiting
-  /// route to indicate that the route should be popped off the [Navigator] with
-  /// an animated transition.
-  void markForPop([dynamic result]);
-
-  /// Marks the [route] to be completed without transition.
-  ///
-  /// During [TransitionDelegate.resolve], this can be called on an exiting
-  /// route to indicate that the route should be completed with the provided
-  /// result and removed from the [Navigator] without an animated transition.
-  void markForComplete([dynamic result]);
-
-  /// Marks the [route] to be removed without transition.
-  ///
-  /// During [TransitionDelegate.resolve], this can be called on an exiting
-  /// route to indicate that the route should be removed from the [Navigator]
-  /// without completing and without an animated transition.
-  void markForRemove();
-}
-
-/// The delegate that decides how pages added and removed from [Navigator.pages]
-/// transition in or out of the screen.
-///
-/// This abstract class implements the API to be called by [Navigator] when it
-/// requires explicit decisions on how the routes transition on or off the screen.
-///
-/// To make route transition decisions, subclass must implement [resolve].
-///
-/// {@tool sample --template=freeform}
-/// The following example demonstrates how to implement a subclass that always
-/// removes or adds routes without animated transitions and puts the removed
-/// routes at the top of the list.
-///
-/// ```dart imports
-/// import 'package:flutter/widgets.dart';
-/// ```
-///
-/// ```dart
-/// class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
-///   @override
-///   Iterable<RouteTransitionRecord> resolve({
-///     List<RouteTransitionRecord> newPageRouteHistory,
-///     Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
-///     Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
-///   }) {
-///     final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
-///
-///     for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
-///       if (pageRoute.isEntering) {
-///         pageRoute.markForAdd();
-///       }
-///       results.add(pageRoute);
-///
-///     }
-///     for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
-///       exitingPageRoute.markForRemove();
-///       final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
-///       if (pagelessRoutes != null) {
-///         for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
-///           pagelessRoute.markForRemove();
-///         }
-///       }
-///       results.add(exitingPageRoute);
-///
-///     }
-///     return results;
-///   }
-/// }
-///
-/// ```
-/// {@end-tool}
-///
-/// See also:
-///
-///  * [Navigator.transitionDelegate], which uses this class to make route
-///    transition decisions.
-///  * [DefaultTransitionDelegate], which implements the default way to decide
-///    how routes transition in or out of the screen.
-abstract class TransitionDelegate<T> {
-  /// Creates a delegate and enables subclass to create a constant class.
-  const TransitionDelegate();
-
-  Iterable<RouteTransitionRecord> _transition({
-    List<RouteTransitionRecord> newPageRouteHistory,
-    Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
-    Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
-  }) {
-    final Iterable<RouteTransitionRecord> results = resolve(
-      newPageRouteHistory: newPageRouteHistory,
-      locationToExitingPageRoute: locationToExitingPageRoute,
-      pageRouteToPagelessRoutes: pageRouteToPagelessRoutes,
-    );
-    // Verifies the integrity after the decisions have been made.
-    //
-    // Here are the rules:
-    // - All the entering routes in newPageRouteHistory must either be pushed or
-    //   added.
-    // - All the exiting routes in locationToExitingPageRoute must either be
-    //   popped, completed or removed.
-    // - All the pageless routes that belong to exiting routes must either be
-    //   popped, completed or removed.
-    // - All the entering routes in the result must preserve the same order as
-    //   the entering routes in newPageRouteHistory, and the result must contain
-    //   all exiting routes.
-    //     ex:
-    //
-    //     newPageRouteHistory = [A, B, C]
-    //
-    //     locationToExitingPageRoute = {A -> D, C -> E}
-    //
-    //     results = [A, B ,C ,D ,E] is valid
-    //     results = [D, A, B ,C ,E] is also valid because exiting route can be
-    //     inserted in any place
-    //
-    //     results = [B, A, C ,D ,E] is invalid because B must be after A.
-    //     results = [A, B, C ,E] is invalid because results must include D.
-    assert(() {
-      final List<RouteTransitionRecord> resultsToVerify = results.toList(growable: false);
-      final Set<RouteTransitionRecord> exitingPageRoutes = locationToExitingPageRoute.values.toSet();
-      // Firstly, verifies all exiting routes have been marked.
-      for (final RouteTransitionRecord exitingPageRoute in exitingPageRoutes) {
-        assert(!exitingPageRoute._debugWaitingForExitDecision);
-        if (pageRouteToPagelessRoutes.containsKey(exitingPageRoute)) {
-          for (final RouteTransitionRecord pagelessRoute in pageRouteToPagelessRoutes[exitingPageRoute]) {
-            assert(!pagelessRoute._debugWaitingForExitDecision);
-          }
-        }
-      }
-      // Secondly, verifies the order of results matches the newPageRouteHistory
-      // and contains all the exiting routes.
-      int indexOfNextRouteInNewHistory = 0;
-
-      for (final _RouteEntry routeEntry in resultsToVerify.cast<_RouteEntry>()) {
-        assert(routeEntry != null);
-        assert(!routeEntry.isEntering && !routeEntry._debugWaitingForExitDecision);
-        if (
-          indexOfNextRouteInNewHistory >= newPageRouteHistory.length ||
-          routeEntry != newPageRouteHistory[indexOfNextRouteInNewHistory]
-        ) {
-          assert(exitingPageRoutes.contains(routeEntry));
-          exitingPageRoutes.remove(routeEntry);
-        } else {
-          indexOfNextRouteInNewHistory += 1;
-        }
-      }
-
-      assert(
-        indexOfNextRouteInNewHistory == newPageRouteHistory.length &&
-        exitingPageRoutes.isEmpty
-      );
-      return true;
-    }());
-
-    return results;
-  }
-
-  /// A method that will be called by the [Navigator] to decide how routes
-  /// transition in or out of the screen when [Navigator.pages] is updated.
-  ///
-  /// The `newPageRouteHistory` list contains all page-based routes in the order
-  /// that will be on the [Navigator]'s history stack after this update
-  /// completes. If a route in `newPageRouteHistory` has its
-  /// [RouteTransitionRecord.isEntering] set to true, this route requires explicit
-  /// decision on how it should transition onto the Navigator. To make a
-  /// decision, call [RouteTransitionRecord.markForPush] or
-  /// [RouteTransitionRecord.markForAdd].
-  ///
-  /// The `locationToExitingPageRoute` contains the pages-based routes that
-  /// are removed from the routes history after page update and require explicit
-  /// decision on how to transition off the screen. This map records page-based
-  /// routes to be removed with the location of the route in the original route
-  /// history before the update. The keys are the locations represented by the
-  /// page-based routes that are directly below the removed routes, and the value
-  /// are the page-based routes to be removed. The location is null if the route
-  /// to be removed is the bottom most route. To make a decision for a removed
-  /// route, call [RouteTransitionRecord.markForPop],
-  /// [RouteTransitionRecord.markForComplete] or
-  /// [RouteTransitionRecord.markForRemove].
-  ///
-  /// The `pageRouteToPagelessRoutes` records the page-based routes and their
-  /// associated pageless routes. If a page-based route is to be removed, its
-  /// associated pageless routes also require explicit decisions on how to
-  /// transition off the screen.
-  ///
-  /// Once all the decisions have been made, this method must merge the removed
-  /// routes and the `newPageRouteHistory` and return the merged result. The
-  /// order in the result will be the order the [Navigator] uses for updating
-  /// the route history. The return list must preserve the same order of routes
-  /// in `newPageRouteHistory`. The removed routes, however, can be inserted
-  /// into the return list freely as long as all of them are included.
-  ///
-  /// For example, consider the following case.
-  ///
-  ///    newPageRouteHistory = [A, B, C]
-  ///
-  ///    locationToExitingPageRoute = {A -> D, C -> E}
-  ///
-  /// The following outputs are valid.
-  ///
-  ///    result = [A, B ,C ,D ,E] is valid
-  ///    result = [D, A, B ,C ,E] is also valid because exiting route can be
-  ///    inserted in any place
-  ///
-  /// The following outputs are invalid.
-  ///
-  ///    result = [B, A, C ,D ,E] is invalid because B must be after A.
-  ///    result = [A, B, C ,E] is invalid because results must include D.
-  ///
-  /// See also:
-  ///
-  ///  * [RouteTransitionRecord.markForPush], which makes route enter the screen
-  ///    with an animated transition.
-  ///  * [RouteTransitionRecord.markForAdd], which makes route enter the screen
-  ///    without an animated transition.
-  ///  * [RouteTransitionRecord.markForPop], which makes route exit the screen
-  ///    with an animated transition.
-  ///  * [RouteTransitionRecord.markForRemove], which does not complete the
-  ///    route and makes it exit the screen without an animated transition.
-  ///  * [RouteTransitionRecord.markForComplete], which completes the route and
-  ///    makes it exit the screen without an animated transition.
-  ///  * [DefaultTransitionDelegate.resolve], which implements the default way
-  ///    to decide how routes transition in or out of the screen.
-  Iterable<RouteTransitionRecord> resolve({
-    List<RouteTransitionRecord> newPageRouteHistory,
-    Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
-    Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
-  });
-}
-
-/// The default implementation of [TransitionDelegate] that the [Navigator] will
-/// use if its [Navigator.transitionDelegate] is not specified.
-///
-/// This transition delegate follows two rules. Firstly, all the entering routes
-/// are placed on top of the exiting routes if they are at the same location.
-/// Secondly, the top most route will always transition with an animated transition.
-/// All the other routes below will either be completed with
-/// [Route.currentResult] or added without an animated transition.
-class DefaultTransitionDelegate<T> extends TransitionDelegate<T> {
-  /// Creates a default transition delegate.
-  const DefaultTransitionDelegate() : super();
-
-  @override
-  Iterable<RouteTransitionRecord> resolve({
-    List<RouteTransitionRecord> newPageRouteHistory,
-    Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
-    Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
-  }) {
-    final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
-    // This method will handle the exiting route and its corresponding pageless
-    // route at this location. It will also recursively check if there is any
-    // other exiting routes above it and handle them accordingly.
-    void handleExitingRoute(RouteTransitionRecord location, bool isLast) {
-      final RouteTransitionRecord exitingPageRoute = locationToExitingPageRoute[location];
-      if (exitingPageRoute == null)
-        return;
-      assert(exitingPageRoute._debugWaitingForExitDecision);
-      final bool hasPagelessRoute = pageRouteToPagelessRoutes.containsKey(exitingPageRoute);
-      final bool isLastExitingPageRoute = isLast && !locationToExitingPageRoute.containsKey(exitingPageRoute);
-      if (isLastExitingPageRoute && !hasPagelessRoute) {
-        exitingPageRoute.markForPop(exitingPageRoute.route.currentResult);
-      } else {
-        exitingPageRoute.markForComplete(exitingPageRoute.route.currentResult);
-      }
-      results.add(exitingPageRoute);
-
-      if (hasPagelessRoute) {
-        final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
-        for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
-          assert(pagelessRoute._debugWaitingForExitDecision);
-          if (isLastExitingPageRoute && pagelessRoute == pagelessRoutes.last) {
-            pagelessRoute.markForPop(pagelessRoute.route.currentResult);
-          } else {
-            pagelessRoute.markForComplete(pagelessRoute.route.currentResult);
-          }
-        }
-      }
-      // It is possible there is another exiting route above this exitingPageRoute.
-      handleExitingRoute(exitingPageRoute, isLast);
-    }
-
-    // Handles exiting route in the beginning of list.
-    handleExitingRoute(null, newPageRouteHistory.isEmpty);
-
-    for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
-      final bool isLastIteration = newPageRouteHistory.last == pageRoute;
-      if (pageRoute.isEntering) {
-        if (!locationToExitingPageRoute.containsKey(pageRoute) && isLastIteration) {
-          pageRoute.markForPush();
-        } else {
-          pageRoute.markForAdd();
-        }
-      }
-      results.add(pageRoute);
-      handleExitingRoute(pageRoute, isLastIteration);
-    }
-    return results;
-  }
-}
-
 /// A widget that manages a set of child widgets with a stack discipline.
 ///
 /// Many apps have a navigator near the top of their widget hierarchy in order
@@ -950,9 +505,8 @@
 /// Mobile apps typically reveal their contents via full-screen elements
 /// called "screens" or "pages". In Flutter these elements are called
 /// routes and they're managed by a [Navigator] widget. The navigator
-/// manages a stack of [Route] objects and provides two ways for managing
-/// the stack, the declarative API [Navigator.pages] or imperative API
-/// [Navigator.push] and [Navigator.pop].
+/// manages a stack of [Route] objects and provides methods for managing
+/// the stack, like [Navigator.push] and [Navigator.pop].
 ///
 /// When your user interface fits this paradigm of a stack, where the user
 /// should be able to _navigate_ back to an earlier element in the stack,
@@ -964,21 +518,6 @@
 /// used in the [Scaffold.appBar] property) can automatically add a back
 /// button for user navigation.
 ///
-/// ## Using the Pages API
-///
-/// The [Navigator] will convert its [Navigator.pages] into a stack of [Route]s
-/// if it is provided. A change in [Navigator.pages] will trigger an update to
-/// the stack of [Route]s. The [Navigator] will update its routes to match the
-/// new configuration of its [Navigator.pages]. To use this API, one can use
-/// [CustomBuilderPage] or create a [Page] subclass and defines a list of
-/// [Page]s for [Navigator.pages]. A [Navigator.onPopPage] callback is also
-/// required to properly clean up the input pages in case of a pop.
-///
-/// By Default, the [Navigator] will use [DefaultTransitionDelegate] to decide
-/// how routes transition in or out of the screen. To customize it, define a
-/// [TransitionDelegate] subclass and provide it to the
-/// [Navigator.transitionDelegate].
-///
 /// ### Displaying a full-screen route
 ///
 /// Although you can create a navigator directly, it's most common to use the
@@ -1194,7 +733,7 @@
 /// ```
 ///
 /// ```dart main
-/// void main() => runApp(MyApp());
+/// void main() => runApp(new MyApp());
 /// ```
 ///
 /// ```dart
@@ -1320,77 +859,17 @@
 class Navigator extends StatefulWidget {
   /// Creates a widget that maintains a stack-based history of child widgets.
   ///
-  /// The [onGenerateRoute], [pages], [onGenerateInitialRoutes],
-  /// [transitionDelegate], [observers]  arguments must not be null.
-  ///
-  /// If the [pages] is not empty, the [onPopPage] must not be null.
+  /// The [onGenerateRoute] argument must not be null.
   const Navigator({
     Key key,
-    this.pages = const <Page<dynamic>>[],
-    this.onPopPage,
     this.initialRoute,
     this.onGenerateInitialRoutes = Navigator.defaultGenerateInitialRoutes,
     this.onGenerateRoute,
     this.onUnknownRoute,
-    this.transitionDelegate = const DefaultTransitionDelegate<dynamic>(),
     this.observers = const <NavigatorObserver>[],
-  }) : assert(pages != null),
-       assert(onGenerateInitialRoutes != null),
-       assert(transitionDelegate != null),
-       assert(observers != null),
+  }) : assert(onGenerateInitialRoutes != null),
        super(key: key);
 
-  /// The list of pages with which to populate the history.
-  ///
-  /// Pages are turned into routes using [Page.createRoute] in a manner
-  /// analogous to how [Widget]s are turned into [Element]s (and [State]s or
-  /// [RenderObject]s) using [Widget.createElement] (and
-  /// [StatefulWidget.createState] or [RenderObjectWidget.createRenderObject]).
-  ///
-  /// When this list is updated, the new list is compared to the previous
-  /// list and the set of routes is updated accordingly.
-  ///
-  /// Some [Route]s do not correspond to [Page] objects, namely, those that are
-  /// added to the history using the [Navigator] API ([push] and friends). A
-  /// [Route] that does not correspond to a [Page] object is called a pageless
-  /// route and is tied to the [Route] that _does_ correspond to a [Page] object
-  /// that is below it in the history.
-  ///
-  /// Pages that are added or removed may be animated as controlled by the
-  /// [transitionDelegate]. If a page is removed that had other pageless routes
-  /// pushed on top of it using [push] and friends, those pageless routes are
-  /// also removed with or without animation as determined by the
-  /// [transitionDelegate].
-  ///
-  /// To use this API, an [onPopPage] callback must also be provided to properly
-  /// clean up this list if a page has been popped.
-  ///
-  /// If [initialRoute] is non-null when the widget is first created, then
-  /// [onGenerateInitialRoutes] is used to generate routes that are above those
-  /// corresponding to [pages] in the initial history.
-  final List<Page<dynamic>> pages;
-
-  /// Called when [pop] is invoked but the current [Route] corresponds to a
-  /// [Page] found in the [pages] list.
-  ///
-  /// The `result` argument is the value with which the route is to complete
-  /// (e.g. the value returned from a dialog).
-  ///
-  /// This callback is responsible for calling [Route.didPop] and returning
-  /// whether this pop is successful.
-  ///
-  /// The [Navigator] widget should be rebuilt with a [pages] list that does not
-  /// contain the [Page] for the given [Route]. The next time the [pages] list
-  /// is updated, if the [Page] corresponding to this [Route] is still present,
-  /// it will be interpreted as a new route to display.
-  final PopPageCallback onPopPage;
-
-  /// The delegate used for deciding how routes transition in or off the screen
-  /// during the [pages] updates.
-  ///
-  /// Defaults to [DefaultTransitionDelegate] if not specified, cannot be null.
-  final TransitionDelegate<dynamic> transitionDelegate;
-
   /// The name of the first route to show.
   ///
   /// Defaults to [Navigator.defaultRouteName].
@@ -2201,14 +1680,6 @@
 // The _RouteLifecycle state machine (only goes down):
 //
 //                    [creation of a _RouteEntry]
-//                                 |
-//                                 +
-//                                 |\
-//                                 | \
-//                                 | staging
-//                                 | /
-//                                 |/
-//                    +-+----------+--+-------+
 //                   /  |             |       |
 //                  /   |             |       |
 //                 /    |             |       |
@@ -2217,7 +1688,7 @@
 //      pushReplace   push*         add*   replace*
 //               \       |            |       |
 //                \      |            |      /
-//                 +--pushing#      adding  /
+//                 +--pushing#        |     /
 //                          \        /     /
 //                           \      /     /
 //                           idle--+-----+
@@ -2243,69 +1714,47 @@
 //   route entry will exit that state.
 // # These states await futures or other events, then transition automatically.
 enum _RouteLifecycle {
-  staging, // we will wait for transition delegate to decide what to do with this route.
-  //
-  // routes that are present:
-  //
+  // routes that are and will be present:
   add, // we'll want to run install, didAdd, etc; a route created by onGenerateInitialRoutes or by the initial widget.pages
-  adding, // we'll want to run install, didAdd, etc; a route created by onGenerateInitialRoutes or by the initial widget.pages
-  // routes that are ready for transition.
   push, // we'll want to run install, didPush, etc; a route added via push() and friends
   pushReplace, // we'll want to run install, didPush, etc; a route added via pushReplace() and friends
   pushing, // we're waiting for the future from didPush to complete
   replace, // we'll want to run install, didReplace, etc; a route added via replace() and friends
   idle, // route is being harmless
-  //
-  // routes that are not present:
-  //
-  // routes that should be included in route announcement and should still listen to transition changes.
+  // routes that are but will not present:
   pop, // we'll want to call didPop
   remove, // we'll want to run didReplace/didRemove etc
-  // routes should not be included in route announcement but should still listen to transition changes.
+  // routes that are not and will not present:
   popping, // we're waiting for the route to call finalizeRoute to switch to dispose
   removing, // we are waiting for subsequent routes to be done animating, then will switch to dispose
-  // routes that are completely removed from the navigator and overlay.
   dispose, // we will dispose the route momentarily
   disposed, // we have disposed the route
 }
 
 typedef _RouteEntryPredicate = bool Function(_RouteEntry entry);
 
-class _RouteEntry extends RouteTransitionRecord {
+class _RouteEntry {
   _RouteEntry(
     this.route, {
       @required _RouteLifecycle initialState,
     }) : assert(route != null),
          assert(initialState != null),
          assert(
-           initialState == _RouteLifecycle.staging ||
            initialState == _RouteLifecycle.add ||
            initialState == _RouteLifecycle.push ||
            initialState == _RouteLifecycle.pushReplace ||
            initialState == _RouteLifecycle.replace
          ),
-         currentState = initialState;
+         currentState = initialState; // ignore: prefer_initializing_formals
 
-  @override
   final Route<dynamic> route;
 
   _RouteLifecycle currentState;
+  Route<dynamic> lastAnnouncedNextRoute; // last argument to Route.didChangeNext
   Route<dynamic> lastAnnouncedPreviousRoute; // last argument to Route.didChangePrevious
   Route<dynamic> lastAnnouncedPoppedNextRoute; // last argument to Route.didPopNext
-  Route<dynamic> lastAnnouncedNextRoute; // last argument to Route.didChangeNext
 
-  bool get hasPage => route.settings is Page;
-
-  bool canUpdateFrom(Page<dynamic> page) {
-    if (currentState.index > _RouteLifecycle.idle.index)
-      return false;
-    if (!hasPage)
-      return false;
-    final Page<dynamic> routePage = route.settings as Page<dynamic>;
-    return page.canUpdate(routePage);
-  }
-
-  void handleAdd({ @required NavigatorState navigator}) {
+  void handleAdd({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) {
     assert(currentState == _RouteLifecycle.add);
     assert(navigator != null);
     assert(navigator._debugLocked);
@@ -2313,7 +1762,13 @@
     route._navigator = navigator;
     route.install();
     assert(route.overlayEntries.isNotEmpty);
-    currentState = _RouteLifecycle.adding;
+    route.didAdd();
+    currentState = _RouteLifecycle.idle;
+    if (isNewFirst) {
+      route.didChangeNext(null);
+    }
+    for (final NavigatorObserver observer in navigator.widget.observers)
+      observer.didPush(route, previousPresent);
   }
 
   void handlePush({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) {
@@ -2383,16 +1838,6 @@
 
   bool doingPop = false;
 
-  void didAdd({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) {
-    route.didAdd();
-    currentState = _RouteLifecycle.idle;
-    if (isNewFirst) {
-      route.didChangeNext(null);
-    }
-    for (final NavigatorObserver observer in navigator.widget.observers)
-      observer.didPush(route, previousPresent);
-  }
-
   void pop<T>(T result) {
     assert(isPresent);
     doingPop = true;
@@ -2406,11 +1851,6 @@
 
   // Route is removed without being completed.
   void remove({ bool isReplaced = false }) {
-    assert(
-      !hasPage || _debugWaitingForExitDecision,
-      'A page-based route cannot be completed using imperative api, provide a '
-      'new list without the corresponding Page to Navigator.pages instead. '
-    );
     if (currentState.index >= _RouteLifecycle.remove.index)
       return;
     assert(isPresent);
@@ -2420,11 +1860,6 @@
 
   // Route completes with `result` and is removed.
   void complete<T>(T result, { bool isReplaced = false }) {
-    assert(
-      !hasPage || _debugWaitingForExitDecision,
-      'A page-based route cannot be completed using imperative api, provide a '
-      'new list without the corresponding Page to Navigator.pages instead. '
-    );
     if (currentState.index >= _RouteLifecycle.remove.index)
       return;
     assert(isPresent);
@@ -2445,25 +1880,8 @@
     currentState = _RouteLifecycle.disposed;
   }
 
-  bool get willBePresent {
-    return currentState.index <= _RouteLifecycle.idle.index &&
-           currentState.index >= _RouteLifecycle.add.index;
-  }
-
-  bool get isPresent {
-    return currentState.index <= _RouteLifecycle.remove.index &&
-           currentState.index >= _RouteLifecycle.add.index;
-  }
-
-  bool get suitableForAnnouncement {
-    return currentState.index <= _RouteLifecycle.removing.index &&
-           currentState.index >= _RouteLifecycle.push.index;
-  }
-
-  bool get suitableForTransitionAnimation {
-    return currentState.index <= _RouteLifecycle.remove.index &&
-           currentState.index >= _RouteLifecycle.push.index;
-  }
+  bool get willBePresent => currentState.index <= _RouteLifecycle.idle.index;
+  bool get isPresent => currentState.index <= _RouteLifecycle.remove.index;
 
   bool shouldAnnounceChangeToNext(Route<dynamic> nextRoute) {
     assert(nextRoute != lastAnnouncedNextRoute);
@@ -2477,76 +1895,17 @@
   }
 
   static final _RouteEntryPredicate isPresentPredicate = (_RouteEntry entry) => entry.isPresent;
-  static final _RouteEntryPredicate suitableForTransitionAnimationPredicate = (_RouteEntry entry) => entry.suitableForTransitionAnimation;
   static final _RouteEntryPredicate willBePresentPredicate = (_RouteEntry entry) => entry.willBePresent;
 
   static _RouteEntryPredicate isRoutePredicate(Route<dynamic> route) {
     return (_RouteEntry entry) => entry.route == route;
   }
-
-  @override
-  bool get isEntering => currentState == _RouteLifecycle.staging;
-
-  @override
-  void markForPush() {
-    assert(
-      isEntering && !_debugWaitingForExitDecision,
-      'This route cannot be marked for push. Either a decision has already been '
-      'made or it does not require an explicit decision on how to transition in.'
-    );
-    currentState = _RouteLifecycle.push;
-  }
-
-  @override
-  void markForAdd() {
-    assert(
-      isEntering && !_debugWaitingForExitDecision,
-      'This route cannot be marked for add. Either a decision has already been '
-      'made or it does not require an explicit decision on how to transition in.'
-    );
-    currentState = _RouteLifecycle.add;
-  }
-
-  @override
-  void markForPop([dynamic result]) {
-    assert(
-      !isEntering && _debugWaitingForExitDecision,
-      'This route cannot be marked for pop. Either a decision has already been '
-      'made or it does not require an explicit decision on how to transition out.'
-    );
-    pop<dynamic>(result);
-    _debugWaitingForExitDecision = false;
-  }
-
-  @override
-  void markForComplete([dynamic result]) {
-    assert(
-      !isEntering && _debugWaitingForExitDecision,
-      'This route cannot be marked for complete. Either a decision has already '
-      'been made or it does not require an explicit decision on how to transition '
-      'out.'
-    );
-    complete<dynamic>(result);
-    _debugWaitingForExitDecision = false;
-  }
-
-  @override
-  void markForRemove() {
-    assert(
-      !isEntering && _debugWaitingForExitDecision,
-      'This route cannot be marked for remove. Either a decision has already '
-      'been made or it does not require an explicit decision on how to transition '
-      'out.'
-    );
-    remove();
-    _debugWaitingForExitDecision = false;
-  }
 }
 
 /// The state for a [Navigator] widget.
 class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
   final GlobalKey<OverlayState> _overlayKey = GlobalKey<OverlayState>();
-  List<_RouteEntry> _history = <_RouteEntry>[];
+  final List<_RouteEntry> _history = <_RouteEntry>[];
 
   /// The [FocusScopeNode] for the [FocusScope] that encloses the routes.
   final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'Navigator Scope');
@@ -2556,40 +1915,20 @@
   @override
   void initState() {
     super.initState();
-    assert(
-      widget.pages.isEmpty || widget.onPopPage != null,
-      'The Navigator.onPopPage must be provided to use the Navigator.pages API',
-    );
     for (final NavigatorObserver observer in widget.observers) {
       assert(observer.navigator == null);
       observer._navigator = this;
     }
-    String initialRoute = widget.initialRoute;
-    if (widget.pages.isNotEmpty) {
-      _history.addAll(
-        widget.pages.map((Page<dynamic> page) => _RouteEntry(
-          page.createRoute(context),
+    // TODO(chunhtai): Uses pages after we add page api.
+    // https://github.com/flutter/flutter/issues/45938
+    _history.addAll(
+      widget.onGenerateInitialRoutes(this, widget.initialRoute ?? Navigator.defaultRouteName)
+        .map((Route<dynamic> route) => _RouteEntry(
+          route,
           initialState: _RouteLifecycle.add,
-        ))
-      );
-    } else {
-      // If there is no page provided, we will need to provide default route
-      // to initialize the navigator.
-      initialRoute = initialRoute ?? Navigator.defaultRouteName;
-    }
-    if (initialRoute != null) {
-      _history.addAll(
-        widget.onGenerateInitialRoutes(
-          this,
-          widget.initialRoute ?? Navigator.defaultRouteName
-        ).map((Route<dynamic> route) =>
-          _RouteEntry(
-            route,
-            initialState: _RouteLifecycle.add,
-          ),
         ),
-      );
-    }
+      ),
+    );
     assert(!_debugLocked);
     assert(() { _debugLocked = true; return true; }());
     _flushHistoryUpdates();
@@ -2599,10 +1938,6 @@
   @override
   void didUpdateWidget(Navigator oldWidget) {
     super.didUpdateWidget(oldWidget);
-    assert(
-      widget.pages.isEmpty || widget.onPopPage != null,
-      'The Navigator.onPopPage must be provided to use the Navigator.pages API',
-    );
     if (oldWidget.observers != widget.observers) {
       for (final NavigatorObserver observer in oldWidget.observers)
         observer._navigator = null;
@@ -2611,31 +1946,10 @@
         observer._navigator = this;
       }
     }
-    if (oldWidget.pages != widget.pages) {
-      assert(
-        widget.pages.isNotEmpty,
-        'To use the Navigator.pages, there must be at least one page in the list.'
-      );
-      _updatePages();
-    }
-
     for (final _RouteEntry entry in _history)
       entry.route.changedExternalState();
   }
 
-  void _debugCheckDuplicatedPageKeys() {
-    assert((){
-      final Set<Key> keyReservation = <Key>{};
-      for (final Page<dynamic> page in widget.pages) {
-        if (page.key != null) {
-          assert(!keyReservation.contains(page.key));
-          keyReservation.add(page.key);
-        }
-      }
-      return true;
-    }());
-  }
-
   @override
   void dispose() {
     assert(!_debugLocked);
@@ -2663,276 +1977,8 @@
 
   String _lastAnnouncedRouteName;
 
-  bool _debugUpdatingPage = false;
-  void _updatePages() {
-    assert(() {
-      assert(!_debugUpdatingPage);
-      _debugCheckDuplicatedPageKeys();
-      _debugUpdatingPage = true;
-      return true;
-    }());
-
-    // This attempts to diff the new pages list (widget.pages) with
-    // the old _RouteEntry[s] list (_history), and produces a new list of
-    // _RouteEntry[s] to be the new list of _history. This method roughly
-    // follows the same outline of RenderObjectElement.updateChildren.
-    //
-    // The cases it tries to optimize for are:
-    //  - the old list is empty
-    //  - All the pages in the new list can match the page-based routes in the old
-    //    list, and their orders are the same.
-    //  - there is an insertion or removal of one or more page-based route in
-    //    only one place in the list
-    // If a page-based route with a key is in both lists, it will be synced.
-    // Page-based routes without keys might be synced but there is no guarantee.
-
-    // The general approach is to sync the entire new list backwards, as follows:
-    // 1. Walk the lists from the bottom, syncing nodes, and record pageless routes,
-    //    until you no longer have matching nodes.
-    // 2. Walk the lists from the top, without syncing nodes, until you no
-    //    longer have matching nodes. We'll sync these nodes at the end. We
-    //    don't sync them now because we want to sync all the nodes in order
-    //    from beginning to end.
-    // At this point we narrowed the old and new lists to the point
-    // where the nodes no longer match.
-    // 3. Walk the narrowed part of the old list to get the list of
-    //    keys.
-    // 4. Walk the narrowed part of the new list forwards:
-    //     * Create a new _RouteEntry for non-keyed items and record them for
-    //       transitionDelegate.
-    //     * Sync keyed items with the source if it exists.
-    // 5. Walk the narrowed part of the old list again to records the
-    //    _RouteEntry[s], as well as pageless routes, needed to be removed for
-    //    transitionDelegate.
-    // 5. Walk the top of the list again, syncing the nodes and recording
-    //    pageless routes.
-    // 6. Use transitionDelegate for explicit decisions on how _RouteEntry[s]
-    //    transition in or off the screens.
-    // 7. Fill pageless routes back into the new history.
-
-    bool needsExplicitDecision = false;
-    int newPagesBottom = 0;
-    int oldEntriesBottom = 0;
-    int newPagesTop = widget.pages.length - 1;
-    int oldEntriesTop = _history.length - 1;
-
-    final List<_RouteEntry> newHistory = <_RouteEntry>[];
-    final Map<_RouteEntry, List<_RouteEntry>> pageRouteToPagelessRoutes = <_RouteEntry, List<_RouteEntry>>{};
-
-    // Updates the bottom of the list.
-    _RouteEntry previousOldPageRouteEntry;
-    while (oldEntriesBottom <= oldEntriesTop) {
-      final _RouteEntry oldEntry = _history[oldEntriesBottom];
-      assert(oldEntry != null && oldEntry.currentState != _RouteLifecycle.disposed);
-      // Records pageless route. The bottom most pageless routes will be
-      // stored in key = null.
-      if (!oldEntry.hasPage) {
-        final List<_RouteEntry> pagelessRoutes = pageRouteToPagelessRoutes.putIfAbsent(
-          previousOldPageRouteEntry,
-          () => <_RouteEntry>[],
-        );
-        pagelessRoutes.add(oldEntry);
-        oldEntriesBottom += 1;
-        continue;
-      }
-      if (newPagesBottom > newPagesTop)
-        break;
-      final Page<dynamic> newPage = widget.pages[newPagesBottom];
-      if (!oldEntry.canUpdateFrom(newPage))
-        break;
-      previousOldPageRouteEntry = oldEntry;
-      oldEntry.route._updateSettings(newPage);
-      newHistory.add(oldEntry);
-      newPagesBottom += 1;
-      oldEntriesBottom += 1;
-    }
-
-    int pagelessRoutesToSkip = 0;
-    // Scans the top of the list until we found a page-based route that cannot be
-    // updated.
-    while ((oldEntriesBottom <= oldEntriesTop) && (newPagesBottom <= newPagesTop)) {
-      final _RouteEntry oldEntry = _history[oldEntriesTop];
-      assert(oldEntry != null && oldEntry.currentState != _RouteLifecycle.disposed);
-      if (!oldEntry.hasPage) {
-        // This route might need to be skipped if we can not find a page above.
-        pagelessRoutesToSkip += 1;
-        oldEntriesTop -= 1;
-        continue;
-      }
-      final Page<dynamic> newPage = widget.pages[newPagesTop];
-      if (!oldEntry.canUpdateFrom(newPage))
-        break;
-      // We found the page for all the consecutive pageless routes below. Those
-      // pageless routes do not need to be skipped.
-      pagelessRoutesToSkip = 0;
-      oldEntriesTop -= 1;
-      newPagesTop -= 1;
-    }
-    // Reverts the pageless routes that cannot be updated.
-    oldEntriesTop += pagelessRoutesToSkip;
-
-    // Scans middle of the old entries and records the page key to old entry map.
-    int oldEntriesBottomToScan = oldEntriesBottom;
-    final Map<LocalKey, _RouteEntry> pageKeyToOldEntry = <LocalKey, _RouteEntry>{};
-    while (oldEntriesBottomToScan <= oldEntriesTop) {
-      final _RouteEntry oldEntry = _history[oldEntriesBottomToScan];
-      oldEntriesBottomToScan += 1;
-      assert(
-        oldEntry != null &&
-        oldEntry.currentState != _RouteLifecycle.disposed
-      );
-      // Pageless routes will be recorded when we update the middle of the old
-      // list.
-      if (!oldEntry.hasPage)
-        continue;
-
-      assert(oldEntry.hasPage);
-
-      final Page<dynamic> page = oldEntry.route.settings as Page<dynamic>;
-      if (page.key == null)
-        continue;
-
-      assert(!pageKeyToOldEntry.containsKey(page.key));
-      pageKeyToOldEntry[page.key] = oldEntry;
-    }
-
-    // Updates the middle of the list.
-    while (newPagesBottom <= newPagesTop) {
-      final Page<dynamic> nextPage = widget.pages[newPagesBottom];
-      newPagesBottom += 1;
-      if (
-        nextPage.key == null ||
-        !pageKeyToOldEntry.containsKey(nextPage.key) ||
-        !pageKeyToOldEntry[nextPage.key].canUpdateFrom(nextPage)
-      ) {
-        // There is no matching key in the old history, we need to create a new
-        // route and wait for the transition delegate to decide how to add
-        // it into the history.
-        final _RouteEntry newEntry = _RouteEntry(
-          nextPage.createRoute(context),
-          initialState: _RouteLifecycle.staging,
-        );
-        needsExplicitDecision = true;
-        assert(
-          newEntry.route.settings == nextPage,
-          'If a route is created from a page, its must have that page as its '
-          'settings.',
-        );
-        newHistory.add(newEntry);
-      } else {
-        // Removes the key from pageKeyToOldEntry to indicate it is taken.
-        final _RouteEntry matchingEntry = pageKeyToOldEntry.remove(nextPage.key);
-        assert(matchingEntry.canUpdateFrom(nextPage));
-        matchingEntry.route._updateSettings(nextPage);
-        newHistory.add(matchingEntry);
-      }
-    }
-
-    // Any remaining old routes that do not have a match will need to be removed.
-    final Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute = <RouteTransitionRecord, RouteTransitionRecord>{};
-    while (oldEntriesBottom <= oldEntriesTop) {
-      final _RouteEntry potentialEntryToRemove = _history[oldEntriesBottom];
-      oldEntriesBottom += 1;
-
-      if (!potentialEntryToRemove.hasPage) {
-        assert(previousOldPageRouteEntry != null);
-        final List<_RouteEntry> pagelessRoutes = pageRouteToPagelessRoutes
-          .putIfAbsent(
-          previousOldPageRouteEntry,
-            () => <_RouteEntry>[]
-        );
-        pagelessRoutes.add(potentialEntryToRemove);
-        assert(() {
-          potentialEntryToRemove._debugWaitingForExitDecision = previousOldPageRouteEntry._debugWaitingForExitDecision;
-          return true;
-        }());
-        continue;
-      }
-
-      final Page<dynamic> potentialPageToRemove = potentialEntryToRemove.route.settings as Page<dynamic>;
-      // Marks for transition delegate to remove if this old page does not have
-      // a key or was not taken during updating the middle of new page.
-      if (
-        potentialPageToRemove.key == null ||
-        pageKeyToOldEntry.containsKey(potentialPageToRemove.key)
-      ) {
-        locationToExitingPageRoute[previousOldPageRouteEntry] = potentialEntryToRemove;
-        assert(() {
-          potentialEntryToRemove._debugWaitingForExitDecision = true;
-          return true;
-        }());
-      }
-      previousOldPageRouteEntry = potentialEntryToRemove;
-    }
-
-    // We've scanned the whole list.
-    assert(oldEntriesBottom == oldEntriesTop + 1);
-    assert(newPagesBottom == newPagesTop + 1);
-    newPagesTop = widget.pages.length - 1;
-    oldEntriesTop = _history.length - 1;
-    // Verifies we either reach the bottom or the oldEntriesBottom must be updatable
-    // by newPagesBottom.
-    assert(() {
-      if (oldEntriesBottom <= oldEntriesTop)
-        return newPagesBottom <= newPagesTop &&
-          _history[oldEntriesBottom].hasPage &&
-          _history[oldEntriesBottom].canUpdateFrom(widget.pages[newPagesBottom]);
-      else
-        return newPagesBottom > newPagesTop;
-    }());
-
-    // Updates the top of the list.
-    while ((oldEntriesBottom <= oldEntriesTop) && (newPagesBottom <= newPagesTop)) {
-      final _RouteEntry oldEntry = _history[oldEntriesBottom];
-      assert(oldEntry != null && oldEntry.currentState != _RouteLifecycle.disposed);
-      if (!oldEntry.hasPage) {
-        assert(previousOldPageRouteEntry != null);
-        final List<_RouteEntry> pagelessRoutes = pageRouteToPagelessRoutes
-          .putIfAbsent(
-          previousOldPageRouteEntry,
-            () => <_RouteEntry>[]
-        );
-        pagelessRoutes.add(oldEntry);
-        continue;
-      }
-      previousOldPageRouteEntry = oldEntry;
-      final Page<dynamic> newPage = widget.pages[newPagesBottom];
-      assert(oldEntry.canUpdateFrom(newPage));
-      oldEntry.route._updateSettings(newPage);
-      newHistory.add(oldEntry);
-      oldEntriesBottom += 1;
-      newPagesBottom += 1;
-    }
-
-    // Finally, uses transition delegate to make explicit decision if needed.
-    needsExplicitDecision = needsExplicitDecision || locationToExitingPageRoute.isNotEmpty;
-    Iterable<_RouteEntry> results = newHistory;
-    if (needsExplicitDecision) {
-      results = widget.transitionDelegate._transition(
-        newPageRouteHistory: newHistory,
-        locationToExitingPageRoute: locationToExitingPageRoute,
-        pageRouteToPagelessRoutes: pageRouteToPagelessRoutes,
-      ).cast<_RouteEntry>();
-    }
-    _history = <_RouteEntry>[];
-    // Adds the leading pageless routes if there is any.
-    if (pageRouteToPagelessRoutes.containsKey(null)) {
-      _history.addAll(pageRouteToPagelessRoutes[null]);
-    }
-    for (final _RouteEntry result in results) {
-      _history.add(result);
-      if (pageRouteToPagelessRoutes.containsKey(result)) {
-        _history.addAll(pageRouteToPagelessRoutes[result]);
-      }
-    }
-    assert(() {_debugUpdatingPage = false; return true;}());
-    assert(() { _debugLocked = true; return true; }());
-    _flushHistoryUpdates();
-    assert(() { _debugLocked = false; return true; }());
-  }
-
   void _flushHistoryUpdates({bool rearrangeOverlay = true}) {
-    assert(_debugLocked && !_debugUpdatingPage);
+    assert(_debugLocked);
     // Clean up the list, sending updates to the routes that changed. Notably,
     // we don't send the didChangePrevious/didChangeNext updates to those that
     // did not change at this point, because we're not yet sure exactly what the
@@ -2941,7 +1987,7 @@
     _RouteEntry next;
     _RouteEntry entry = _history[index];
     _RouteEntry previous = index > 0 ? _history[index - 1] : null;
-    bool canRemoveOrAdd = false; // Whether there is a fully opaque route on top to silently remove or add route underneath.
+    bool canRemove = false;
     Route<dynamic> poppedRoute; // The route that should trigger didPopNext on the top active route.
     bool seenTopActiveRoute = false; // Whether we've seen the route that would get didPopNext.
     final List<_RouteEntry> toBeDisposed = <_RouteEntry>[];
@@ -2951,21 +1997,12 @@
           assert(rearrangeOverlay);
           entry.handleAdd(
             navigator: this,
+            previous: previous?.route,
+            previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
+            isNewFirst: next == null,
           );
-          assert(entry.currentState == _RouteLifecycle.adding);
+          assert(entry.currentState == _RouteLifecycle.idle);
           continue;
-        case _RouteLifecycle.adding:
-          if (canRemoveOrAdd || next == null) {
-            entry.didAdd(
-              navigator: this,
-              previous: previous?.route,
-              previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
-              isNewFirst: next == null
-            );
-            assert(entry.currentState == _RouteLifecycle.idle);
-            continue;
-          }
-          break;
         case _RouteLifecycle.push:
         case _RouteLifecycle.pushReplace:
         case _RouteLifecycle.replace:
@@ -2994,7 +2031,7 @@
           seenTopActiveRoute = true;
           // This route is idle, so we are allowed to remove subsequent (earlier)
           // routes that are waiting to be removed silently:
-          canRemoveOrAdd = true;
+          canRemove = true;
           break;
         case _RouteLifecycle.pop:
           if (!seenTopActiveRoute) {
@@ -3007,7 +2044,6 @@
             previousPresent: _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route,
           );
           assert(entry.currentState == _RouteLifecycle.popping);
-          canRemoveOrAdd = true;
           break;
         case _RouteLifecycle.popping:
           // Will exit this state when animation completes.
@@ -3025,7 +2061,7 @@
           assert(entry.currentState == _RouteLifecycle.removing);
           continue;
         case _RouteLifecycle.removing:
-          if (!canRemoveOrAdd && next != null) {
+          if (!canRemove && next != null) {
             // We aren't allowed to remove this route yet.
             break;
           }
@@ -3037,7 +2073,6 @@
           entry = next;
           break;
         case _RouteLifecycle.disposed:
-        case _RouteLifecycle.staging:
           assert(false);
           break;
       }
@@ -3073,11 +2108,7 @@
     int index = _history.length - 1;
     while (index >= 0) {
       final _RouteEntry entry = _history[index];
-      if (!entry.suitableForAnnouncement) {
-        index -= 1;
-        continue;
-      }
-      final _RouteEntry next = _getRouteAfter(index + 1, _RouteEntry.suitableForTransitionAnimationPredicate);
+      final _RouteEntry next = _getRouteAfter(index + 1, _RouteEntry.isPresentPredicate);
 
       if (next?.route != entry.lastAnnouncedNextRoute) {
         if (entry.shouldAnnounceChangeToNext(next?.route)) {
@@ -3085,7 +2116,7 @@
         }
         entry.lastAnnouncedNextRoute = next?.route;
       }
-      final _RouteEntry previous = _getRouteBefore(index - 1, _RouteEntry.suitableForTransitionAnimationPredicate);
+      final _RouteEntry previous = _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate);
       if (previous?.route != entry.lastAnnouncedPreviousRoute) {
         entry.route.didChangePrevious(previous?.route);
         entry.lastAnnouncedPreviousRoute = previous?.route;
@@ -3584,12 +2615,7 @@
       return true;
     }());
     final _RouteEntry entry = _history.lastWhere(_RouteEntry.isPresentPredicate);
-    if (entry.hasPage) {
-      if (widget.onPopPage(entry.route, result))
-        entry.currentState = _RouteLifecycle.pop;
-    } else {
-      entry.pop<T>(result);
-    }
+    entry.pop<T>(result);
     if (entry.currentState == _RouteLifecycle.pop) {
       // Flush the history if the route actually wants to be popped (the pop
       // wasn't handled internally).
diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart
index 51855e6..cc01fdb 100644
--- a/packages/flutter/test/widgets/navigator_test.dart
+++ b/packages/flutter/test/widgets/navigator_test.dart
@@ -1708,666 +1708,6 @@
     await tester.pump(const Duration(seconds: 1));
     expect(tickCount, 4);
   });
-
-  group('Page api', (){
-    Widget buildNavigator(
-      List<Page<dynamic>> pages,
-      PopPageCallback onPopPage, [
-        GlobalKey<NavigatorState> key,
-        TransitionDelegate<dynamic> transitionDelegate
-      ]) {
-      return MediaQuery(
-        data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
-        child: Localizations(
-          locale: const Locale('en', 'US'),
-          delegates: const <LocalizationsDelegate<dynamic>>[
-            DefaultMaterialLocalizations.delegate,
-            DefaultWidgetsLocalizations.delegate
-          ],
-          child: Directionality(
-            textDirection: TextDirection.ltr,
-            child: Navigator(
-              key: key,
-              pages: pages,
-              onPopPage: onPopPage,
-              transitionDelegate: transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
-            ),
-          ),
-        ),
-      );
-    }
-
-    testWidgets('can initialize with pages list', (WidgetTester tester) async {
-      final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
-      final List<TestPage> myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name:'initial'),
-        const TestPage(key: ValueKey<String>('2'), name:'second'),
-        const TestPage(key: ValueKey<String>('3'), name:'third'),
-      ];
-
-      bool onPopPage(Route<dynamic> route, dynamic result) {
-        myPages.removeWhere((Page<dynamic> page) => route.settings == page);
-        return route.didPop(result);
-      }
-
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      expect(find.text('third'), findsOneWidget);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('initial'), findsNothing);
-
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('third'), findsNothing);
-      expect(find.text('second'), findsOneWidget);
-      expect(find.text('initial'), findsNothing);
-
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('third'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('initial'), findsOneWidget);
-    });
-
-    testWidgets('can push and pop pages using page api', (WidgetTester tester) async {
-      Animation<double> secondaryAnimationOfRouteOne;
-      Animation<double> primaryAnimationOfRouteOne;
-      Animation<double> secondaryAnimationOfRouteTwo;
-      Animation<double> primaryAnimationOfRouteTwo;
-      Animation<double> secondaryAnimationOfRouteThree;
-      Animation<double> primaryAnimationOfRouteThree;
-      final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
-      List<Page<dynamic>> myPages = <Page<dynamic>>[
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('1'),
-          name:'initial',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteOne = secondaryAnimation;
-                primaryAnimationOfRouteOne = animation;
-                return const Text('initial');
-              },
-            );
-          },
-        ),
-      ];
-
-      bool onPopPage(Route<dynamic> route, dynamic result) {
-        myPages.removeWhere((Page<dynamic> page) => route.settings == page);
-        return route.didPop(result);
-      }
-
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      expect(find.text('initial'), findsOneWidget);
-
-      myPages = <Page<dynamic>>[
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('1'),
-          name:'initial',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteOne = secondaryAnimation;
-                primaryAnimationOfRouteOne = animation;
-                return const Text('initial');
-              },
-            );
-          },
-        ),
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('2'),
-          name:'second',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteTwo = secondaryAnimation;
-                primaryAnimationOfRouteTwo = animation;
-                return const Text('second');
-              },
-            );
-          },
-        ),
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('3'),
-          name:'third',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteThree = secondaryAnimation;
-                primaryAnimationOfRouteThree = animation;
-                return const Text('third');
-              },
-            );
-          },
-        )
-      ];
-
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      // The third page is transitioning, and the secondary animation of first
-      // page should chain with the third page. The animation of second page
-      // won't start until the third page finishes transition.
-      expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteThree.value);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
-      expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.forward);
-
-      await tester.pump(const Duration(milliseconds: 30));
-      expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteThree.value);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
-      expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteThree.value, 0.1);
-      await tester.pumpAndSettle();
-      // After transition finishes, the routes' animations are correctly chained.
-      expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-      expect(find.text('third'), findsOneWidget);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('initial'), findsNothing);
-      // Starts pops the pages using page api and verify the animations chain
-      // correctly.
-
-      myPages = <Page<dynamic>>[
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('1'),
-          name:'initial',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteOne = secondaryAnimation;
-                primaryAnimationOfRouteOne = animation;
-                return const Text('initial');
-              },
-            );
-          },
-        ),
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('2'),
-          name:'second',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteTwo = secondaryAnimation;
-                primaryAnimationOfRouteTwo = animation;
-                return const Text('second');
-              },
-            );
-          },
-        ),
-      ];
-
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      await tester.pump(const Duration(milliseconds: 30));
-      expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteThree.value, 0.9);
-      await tester.pumpAndSettle();
-      expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-    });
-
-    testWidgets('can modify routes history and secondary animation still works', (WidgetTester tester) async {
-      final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
-      Animation<double> secondaryAnimationOfRouteOne;
-      Animation<double> primaryAnimationOfRouteOne;
-      Animation<double> secondaryAnimationOfRouteTwo;
-      Animation<double> primaryAnimationOfRouteTwo;
-      Animation<double> secondaryAnimationOfRouteThree;
-      Animation<double> primaryAnimationOfRouteThree;
-      List<Page<dynamic>> myPages = <CustomBuilderPage<void>>[
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('1'),
-          name:'initial',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteOne = secondaryAnimation;
-                primaryAnimationOfRouteOne = animation;
-                return const Text('initial');
-              },
-            );
-          },
-        ),
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('2'),
-          name:'second',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteTwo = secondaryAnimation;
-                primaryAnimationOfRouteTwo = animation;
-                return const Text('second');
-              },
-            );
-          },
-        ),
-        CustomBuilderPage<void>(
-          key: const ValueKey<String>('3'),
-          name:'third',
-          routeBuilder: (BuildContext context, RouteSettings settings) {
-            return PageRouteBuilder<void>(
-              settings: settings,
-              pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
-                secondaryAnimationOfRouteThree = secondaryAnimation;
-                primaryAnimationOfRouteThree = animation;
-                return const Text('third');
-              },
-            );
-          },
-        ),
-      ];
-      bool onPopPage(Route<dynamic> route, dynamic result) {
-        myPages.removeWhere((Page<dynamic> page) => route.settings == page);
-        return route.didPop(result);
-      }
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      expect(find.text('third'), findsOneWidget);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('initial'), findsNothing);
-      expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-
-      myPages = myPages.reversed.toList();
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      // Reversed routes are still chained up correctly.
-      expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
-
-      navigator.currentState.pop();
-      await tester.pump();
-      await tester.pump(const Duration(milliseconds: 30));
-      expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteOne.value, 0.9);
-      await tester.pumpAndSettle();
-      expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-
-      navigator.currentState.pop();
-      await tester.pump();
-      await tester.pump(const Duration(milliseconds: 30));
-      expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
-      expect(primaryAnimationOfRouteTwo.value, 0.9);
-      expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-      await tester.pumpAndSettle();
-      expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
-      expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
-      expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
-      expect(primaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
-      expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-      expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
-    });
-
-    testWidgets('can work with pageless route', (WidgetTester tester) async {
-      final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
-      List<TestPage> myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name:'initial'),
-        const TestPage(key: ValueKey<String>('2'), name:'second'),
-      ];
-
-      bool onPopPage(Route<dynamic> route, dynamic result) {
-        myPages.removeWhere((Page<dynamic> page) => route.settings == page);
-        return route.didPop(result);
-      }
-
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      expect(find.text('second'), findsOneWidget);
-      expect(find.text('initial'), findsNothing);
-      // Pushes two pageless routes to second page route
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('second-pageless1'),
-          settings: null,
-        )
-      );
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('second-pageless2'),
-          settings: null,
-        )
-      );
-      await tester.pumpAndSettle();
-      // Now the history should look like
-      // [initial, second, second-pageless1, second-pageless2].
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsOneWidget);
-
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name:'initial'),
-        const TestPage(key: ValueKey<String>('2'), name:'second'),
-        const TestPage(key: ValueKey<String>('3'), name:'third'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      await tester.pumpAndSettle();
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(find.text('third'), findsOneWidget);
-
-      // Pushes one pageless routes to third page route
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('third-pageless1'),
-          settings: null,
-        )
-      );
-      await tester.pumpAndSettle();
-      // Now the history should look like
-      // [initial, second, second-pageless1, second-pageless2, third, third-pageless1].
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(find.text('third'), findsNothing);
-      expect(find.text('third-pageless1'), findsOneWidget);
-
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name:'initial'),
-        const TestPage(key: ValueKey<String>('3'), name:'third'),
-        const TestPage(key: ValueKey<String>('2'), name:'second'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      // Swaps the order without any adding or removing should not trigger any
-      // transition. The routes should update without a pumpAndSettle
-      // Now the history should look like
-      // [initial, third, third-pageless1, second, second-pageless1, second-pageless2].
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('third'), findsNothing);
-      expect(find.text('third-pageless1'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsOneWidget);
-      // Pops the route one by one to make sure the order is correct.
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('third'), findsNothing);
-      expect(find.text('third-pageless1'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsOneWidget);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(myPages.length, 3);
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('third'), findsNothing);
-      expect(find.text('third-pageless1'), findsNothing);
-      expect(find.text('second'), findsOneWidget);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(myPages.length, 3);
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('third'), findsNothing);
-      expect(find.text('third-pageless1'), findsOneWidget);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(myPages.length, 2);
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('initial'), findsNothing);
-      expect(find.text('third'), findsOneWidget);
-      expect(find.text('third-pageless1'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(myPages.length, 2);
-      navigator.currentState.pop();
-      await tester.pumpAndSettle();
-      expect(find.text('initial'), findsOneWidget);
-      expect(find.text('third'), findsNothing);
-      expect(find.text('third-pageless1'), findsNothing);
-      expect(find.text('second'), findsNothing);
-      expect(find.text('second-pageless1'), findsNothing);
-      expect(find.text('second-pageless2'), findsNothing);
-      expect(myPages.length, 1);
-    });
-
-    testWidgets('complex case 1', (WidgetTester tester) async {
-      final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
-      List<TestPage> myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name: 'initial'),
-      ];
-      bool onPopPage(Route<dynamic> route, dynamic result) {
-        myPages.removeWhere((Page<dynamic> page) => route.settings == page);
-        return route.didPop(result);
-      }
-
-      // Add initial page route with one pageless route.
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      bool initialPageless1Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('initial-pageless1'),
-          settings: null,
-        )
-      ).then((_) => initialPageless1Completed = true);
-      await tester.pumpAndSettle();
-
-      // Pushes second page route with two pageless routes.
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name: 'initial'),
-        const TestPage(key: ValueKey<String>('2'), name: 'second'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      await tester.pumpAndSettle();
-      bool secondPageless1Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('second-pageless1'),
-          settings: null,
-        )
-      ).then((_) => secondPageless1Completed = true);
-      await tester.pumpAndSettle();
-      bool secondPageless2Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('second-pageless2'),
-          settings: null,
-        )
-      ).then((_) => secondPageless2Completed = true);
-      await tester.pumpAndSettle();
-
-      // Pushes third page route with one pageless route.
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name: 'initial'),
-        const TestPage(key: ValueKey<String>('2'), name: 'second'),
-        const TestPage(key: ValueKey<String>('3'), name: 'third'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      await tester.pumpAndSettle();
-      bool thirdPageless1Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('third-pageless1'),
-          settings: null,
-        )
-      ).then((_) => thirdPageless1Completed = true);
-      await tester.pumpAndSettle();
-
-      // Nothing has been popped.
-      expect(initialPageless1Completed, false);
-      expect(secondPageless1Completed, false);
-      expect(secondPageless2Completed, false);
-      expect(thirdPageless1Completed, false);
-
-      // Switches order and removes the initial page route.
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('3'), name: 'third'),
-        const TestPage(key: ValueKey<String>('2'), name: 'second'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      // The pageless route of initial page route should be completed.
-      expect(initialPageless1Completed, true);
-      expect(secondPageless1Completed, false);
-      expect(secondPageless2Completed, false);
-      expect(thirdPageless1Completed, false);
-
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('3'), name: 'third'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      await tester.pumpAndSettle();
-      expect(secondPageless1Completed, true);
-      expect(secondPageless2Completed, true);
-      expect(thirdPageless1Completed, false);
-
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('4'), name: 'forth'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
-      expect(thirdPageless1Completed, true);
-      await tester.pumpAndSettle();
-      expect(find.text('forth'), findsOneWidget);
-    });
-
-    testWidgets('complex case 1 - with always remove transition delegate', (WidgetTester tester) async {
-      final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
-      final AlwaysRemoveTransitionDelegate transitionDelegate = AlwaysRemoveTransitionDelegate();
-      List<TestPage> myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name: 'initial'),
-      ];
-      bool onPopPage(Route<dynamic> route, dynamic result) {
-        myPages.removeWhere((Page<dynamic> page) => route.settings == page);
-        return route.didPop(result);
-      }
-
-      // Add initial page route with one pageless route.
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
-      bool initialPageless1Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('initial-pageless1'),
-          settings: null,
-        )
-      ).then((_) => initialPageless1Completed = true);
-      await tester.pumpAndSettle();
-
-      // Pushes second page route with two pageless routes.
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name: 'initial'),
-        const TestPage(key: ValueKey<String>('2'), name: 'second'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
-      bool secondPageless1Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('second-pageless1'),
-          settings: null,
-        )
-      ).then((_) => secondPageless1Completed = true);
-      await tester.pumpAndSettle();
-      bool secondPageless2Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('second-pageless2'),
-          settings: null,
-        )
-      ).then((_) => secondPageless2Completed = true);
-      await tester.pumpAndSettle();
-
-      // Pushes third page route with one pageless route.
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('1'), name: 'initial'),
-        const TestPage(key: ValueKey<String>('2'), name: 'second'),
-        const TestPage(key: ValueKey<String>('3'), name: 'third'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
-      bool thirdPageless1Completed = false;
-      navigator.currentState.push(
-        MaterialPageRoute<void>(
-          builder: (BuildContext context) => const Text('third-pageless1'),
-          settings: null,
-        )
-      ).then((_) => thirdPageless1Completed = true);
-      await tester.pumpAndSettle();
-
-      // Nothing has been popped.
-      expect(initialPageless1Completed, false);
-      expect(secondPageless1Completed, false);
-      expect(secondPageless2Completed, false);
-      expect(thirdPageless1Completed, false);
-
-      // Switches order and removes the initial page route.
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('3'), name: 'third'),
-        const TestPage(key: ValueKey<String>('2'), name: 'second'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
-      // The pageless route of initial page route should be removed without complete.
-      expect(initialPageless1Completed, false);
-      expect(secondPageless1Completed, false);
-      expect(secondPageless2Completed, false);
-      expect(thirdPageless1Completed, false);
-
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('3'), name: 'third'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
-      await tester.pumpAndSettle();
-      expect(initialPageless1Completed, false);
-      expect(secondPageless1Completed, false);
-      expect(secondPageless2Completed, false);
-      expect(thirdPageless1Completed, false);
-
-      myPages = <TestPage>[
-        const TestPage(key: ValueKey<String>('4'), name: 'forth'),
-      ];
-      await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
-      await tester.pump();
-      expect(initialPageless1Completed, false);
-      expect(secondPageless1Completed, false);
-      expect(secondPageless2Completed, false);
-      expect(thirdPageless1Completed, false);
-      expect(find.text('forth'), findsOneWidget);
-    });
-
-  });
 }
 
 class _TickingWidget extends StatefulWidget {
@@ -2402,62 +1742,6 @@
   }
 }
 
-class AlwaysRemoveTransitionDelegate extends TransitionDelegate<void> {
-  @override
-  Iterable<RouteTransitionRecord> resolve({
-    List<RouteTransitionRecord> newPageRouteHistory,
-    Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
-    Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
-  }) {
-    final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
-    void handleExitingRoute(RouteTransitionRecord location) {
-      if (!locationToExitingPageRoute.containsKey(location))
-        return;
-
-      final RouteTransitionRecord exitingPageRoute = locationToExitingPageRoute[location];
-      final bool hasPagelessRoute = pageRouteToPagelessRoutes.containsKey(exitingPageRoute);
-
-      exitingPageRoute.markForRemove();
-      results.add(exitingPageRoute);
-
-      if (hasPagelessRoute) {
-        final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
-        for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
-          pagelessRoute.markForRemove();
-        }
-      }
-      handleExitingRoute(exitingPageRoute);
-    }
-    handleExitingRoute(null);
-
-    for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
-      if (pageRoute.isEntering) {
-        pageRoute.markForAdd();
-      }
-      results.add(pageRoute);
-      handleExitingRoute(pageRoute);
-
-    }
-    return results;
-  }
-}
-
-class TestPage extends Page<void> {
-  const TestPage({
-    LocalKey key,
-    String name,
-    Object arguments,
-  }) : super(key: key, name: name, arguments: arguments);
-
-  @override
-  Route<void> createRoute(BuildContext context) {
-    return MaterialPageRoute<void>(
-      builder: (BuildContext context) => Text(name),
-      settings: this,
-    );
-  }
-}
-
 class NoAnimationPageRoute extends PageRouteBuilder<void> {
   NoAnimationPageRoute({WidgetBuilder pageBuilder})
       : super(pageBuilder: (BuildContext context, __, ___) {