binding.dart 47 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:async';
6
import 'dart:developer' as developer;
7
import 'dart:ui' show AccessibilityFeatures, AppLifecycleState, FrameTiming, Locale, PlatformDispatcher, TimingsCallback;
8

9
import 'package:flutter/foundation.dart';
Ian Hickson's avatar
Ian Hickson committed
10
import 'package:flutter/gestures.dart';
11
import 'package:flutter/rendering.dart';
12
import 'package:flutter/scheduler.dart';
Ian Hickson's avatar
Ian Hickson committed
13
import 'package:flutter/services.dart';
14

15
import 'app.dart';
16
import 'debug.dart';
17
import 'focus_manager.dart';
18
import 'framework.dart';
19
import 'platform_menu_bar.dart';
20
import 'router.dart';
21
import 'service_extensions.dart';
22
import 'view.dart';
23
import 'widget_inspector.dart';
24

25 26
export 'dart:ui' show AppLifecycleState, Locale;

27 28
/// Interface for classes that register with the Widgets layer binding.
///
29
/// When used as a mixin, provides no-op method implementations.
30
///
31
/// See [WidgetsBinding.addObserver] and [WidgetsBinding.removeObserver].
32 33 34 35 36
///
/// This class can be extended directly, to get default behaviors for all of the
/// handlers, or can used with the `implements` keyword, in which case all the
/// handlers must be implemented (and the analyzer will list those that have
/// been omitted).
37
///
38 39
/// {@tool dartpad}
/// This sample shows how to implement parts of the [State] and
40 41 42
/// [WidgetsBindingObserver] protocols necessary to react to application
/// lifecycle messages. See [didChangeAppLifecycleState].
///
43
/// ** See code in examples/api/lib/widgets/binding/widget_binding_observer.0.dart **
44
///
45
/// {@end-tool}
46 47 48
///
/// To respond to other notifications, replace the [didChangeAppLifecycleState]
/// method above with other methods from this class.
49 50 51 52 53 54 55 56 57 58 59 60 61
abstract class WidgetsBindingObserver {
  /// Called when the system tells the app to pop the current route.
  /// For example, on Android, this is called when the user presses
  /// the back button.
  ///
  /// Observers are notified in registration order until one returns
  /// true. If none return true, the application quits.
  ///
  /// Observers are expected to return true if they were able to
  /// handle the notification, for example by closing an active dialog
  /// box, and false otherwise. The [WidgetsApp] widget uses this
  /// mechanism to notify the [Navigator] widget that it should pop
  /// its current route if possible.
62 63 64
  ///
  /// This method exposes the `popRoute` notification from
  /// [SystemChannels.navigation].
65
  Future<bool> didPopRoute() => Future<bool>.value(false);
66

67
  /// Called when the host tells the application to push a new route onto the
68 69 70
  /// navigator.
  ///
  /// Observers are expected to return true if they were able to
71
  /// handle the notification. Observers are notified in registration
72
  /// order until one returns true.
73 74 75
  ///
  /// This method exposes the `pushRoute` notification from
  /// [SystemChannels.navigation].
76
  Future<bool> didPushRoute(String route) => Future<bool>.value(false);
77

78 79 80 81 82 83 84 85 86 87 88 89 90
  /// Called when the host tells the application to push a new
  /// [RouteInformation] and a restoration state onto the router.
  ///
  /// Observers are expected to return true if they were able to
  /// handle the notification. Observers are notified in registration
  /// order until one returns true.
  ///
  /// This method exposes the `pushRouteInformation` notification from
  /// [SystemChannels.navigation].
  ///
  /// The default implementation is to call the [didPushRoute] directly with the
  /// [RouteInformation.location].
  Future<bool> didPushRouteInformation(RouteInformation routeInformation) {
91
    return didPushRoute(routeInformation.location!);
92 93
  }

94 95
  /// Called when the application's dimensions change. For example,
  /// when a phone is rotated.
96
  ///
97 98
  /// This method exposes notifications from
  /// [dart:ui.PlatformDispatcher.onMetricsChanged].
99
  ///
100
  /// {@tool snippet}
101 102 103 104 105 106
  ///
  /// This [StatefulWidget] implements the parts of the [State] and
  /// [WidgetsBindingObserver] protocols necessary to react when the device is
  /// rotated (or otherwise changes dimensions).
  ///
  /// ```dart
107
  /// class MetricsReactor extends StatefulWidget {
108
  ///   const MetricsReactor({ super.key });
109 110
  ///
  ///   @override
111
  ///   State<MetricsReactor> createState() => _MetricsReactorState();
112 113
  /// }
  ///
114
  /// class _MetricsReactorState extends State<MetricsReactor> with WidgetsBindingObserver {
115
  ///   late Size _lastSize;
116
  ///
117 118 119
  ///   @override
  ///   void initState() {
  ///     super.initState();
120 121
  ///     _lastSize = WidgetsBinding.instance.window.physicalSize;
  ///     WidgetsBinding.instance.addObserver(this);
122 123 124 125
  ///   }
  ///
  ///   @override
  ///   void dispose() {
126
  ///     WidgetsBinding.instance.removeObserver(this);
127 128 129 130 131
  ///     super.dispose();
  ///   }
  ///
  ///   @override
  ///   void didChangeMetrics() {
132
  ///     setState(() { _lastSize = WidgetsBinding.instance.window.physicalSize; });
133 134 135 136
  ///   }
  ///
  ///   @override
  ///   Widget build(BuildContext context) {
137
  ///     return Text('Current size: $_lastSize');
138 139 140
  ///   }
  /// }
  /// ```
141
  /// {@end-tool}
142 143 144 145 146 147 148 149 150
  ///
  /// In general, this is unnecessary as the layout system takes care of
  /// automatically recomputing the application geometry when the application
  /// size changes.
  ///
  /// See also:
  ///
  ///  * [MediaQuery.of], which provides a similar service with less
  ///    boilerplate.
151
  void didChangeMetrics() { }
152

153 154 155 156 157 158
  /// Called when the platform's text scale factor changes.
  ///
  /// This typically happens as the result of the user changing system
  /// preferences, and it should affect all of the text sizes in the
  /// application.
  ///
159 160
  /// This method exposes notifications from
  /// [dart:ui.PlatformDispatcher.onTextScaleFactorChanged].
161
  ///
162
  /// {@tool snippet}
163 164 165
  ///
  /// ```dart
  /// class TextScaleFactorReactor extends StatefulWidget {
166
  ///   const TextScaleFactorReactor({ super.key });
167 168
  ///
  ///   @override
169
  ///   State<TextScaleFactorReactor> createState() => _TextScaleFactorReactorState();
170 171 172 173 174 175
  /// }
  ///
  /// class _TextScaleFactorReactorState extends State<TextScaleFactorReactor> with WidgetsBindingObserver {
  ///   @override
  ///   void initState() {
  ///     super.initState();
176
  ///     WidgetsBinding.instance.addObserver(this);
177 178 179 180
  ///   }
  ///
  ///   @override
  ///   void dispose() {
181
  ///     WidgetsBinding.instance.removeObserver(this);
182 183 184
  ///     super.dispose();
  ///   }
  ///
185
  ///   late double _lastTextScaleFactor;
186 187 188
  ///
  ///   @override
  ///   void didChangeTextScaleFactor() {
189
  ///     setState(() { _lastTextScaleFactor = WidgetsBinding.instance.window.textScaleFactor; });
190 191 192 193
  ///   }
  ///
  ///   @override
  ///   Widget build(BuildContext context) {
194
  ///     return Text('Current scale factor: $_lastTextScaleFactor');
195 196 197
  ///   }
  /// }
  /// ```
198
  /// {@end-tool}
199 200 201 202 203 204 205
  ///
  /// See also:
  ///
  ///  * [MediaQuery.of], which provides a similar service with less
  ///    boilerplate.
  void didChangeTextScaleFactor() { }

206 207
  /// Called when the platform brightness changes.
  ///
208 209
  /// This method exposes notifications from
  /// [dart:ui.PlatformDispatcher.onPlatformBrightnessChanged].
210 211
  void didChangePlatformBrightness() { }

212 213 214
  /// Called when the system tells the app that the user's locale has
  /// changed. For example, if the user changes the system language
  /// settings.
215
  ///
216 217
  /// This method exposes notifications from
  /// [dart:ui.PlatformDispatcher.onLocaleChanged].
218
  void didChangeLocales(List<Locale>? locales) { }
219 220 221

  /// Called when the system puts the app in the background or returns
  /// the app to the foreground.
222 223 224
  ///
  /// An example of implementing this method is provided in the class-level
  /// documentation for the [WidgetsBindingObserver] class.
225 226
  ///
  /// This method exposes notifications from [SystemChannels.lifecycle].
227
  void didChangeAppLifecycleState(AppLifecycleState state) { }
228 229

  /// Called when the system is running low on memory.
230 231 232
  ///
  /// This method exposes the `memoryPressure` notification from
  /// [SystemChannels.system].
233
  void didHaveMemoryPressure() { }
234 235 236 237

  /// Called when the system changes the set of currently active accessibility
  /// features.
  ///
238 239
  /// This method exposes notifications from
  /// [dart:ui.PlatformDispatcher.onAccessibilityFeaturesChanged].
240
  void didChangeAccessibilityFeatures() { }
Ian Hickson's avatar
Ian Hickson committed
241
}
242

243
/// The glue between the widgets layer and the Flutter engine.
244
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
245
  @override
246
  void initInstances() {
Ian Hickson's avatar
Ian Hickson committed
247 248
    super.initInstances();
    _instance = this;
249 250 251 252 253 254

    assert(() {
      _debugAddStackFilters();
      return true;
    }());

255 256 257 258
    // Initialization of [_buildOwner] has to be done after
    // [super.initInstances] is called, as it requires [ServicesBinding] to
    // properly setup the [defaultBinaryMessenger] instance.
    _buildOwner = BuildOwner();
259
    buildOwner!.onBuildScheduled = _handleBuildScheduled;
260 261
    platformDispatcher.onLocaleChanged = handleLocaleChanged;
    platformDispatcher.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
262
    SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
263 264 265 266
    assert(() {
      FlutterErrorDetails.propertiesTransformers.add(debugTransformDebugCreator);
      return true;
    }());
267
    platformMenuDelegate = DefaultPlatformMenuDelegate();
268 269
  }

270 271 272 273 274 275 276 277
  /// The current [WidgetsBinding], if one has been created.
  ///
  /// Provides access to the features exposed by this mixin. The binding must
  /// be initialized before using this getter; this is typically done by calling
  /// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
  static WidgetsBinding get instance => BindingBase.checkInstance(_instance);
  static WidgetsBinding? _instance;

278 279 280 281 282
  void _debugAddStackFilters() {
    const PartialStackFrame elementInflateWidget = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'Element', method: 'inflateWidget');
    const PartialStackFrame elementUpdateChild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'Element', method: 'updateChild');
    const PartialStackFrame elementRebuild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'Element', method: 'rebuild');
    const PartialStackFrame componentElementPerformRebuild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'ComponentElement', method: 'performRebuild');
Dan Field's avatar
Dan Field committed
283
    const PartialStackFrame componentElementFirstBuild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'ComponentElement', method: '_firstBuild');
284
    const PartialStackFrame componentElementMount = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'ComponentElement', method: 'mount');
Dan Field's avatar
Dan Field committed
285
    const PartialStackFrame statefulElementFirstBuild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'StatefulElement', method: '_firstBuild');
286
    const PartialStackFrame singleChildMount = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'SingleChildRenderObjectElement', method: 'mount');
Dan Field's avatar
Dan Field committed
287
    const PartialStackFrame statefulElementRebuild = PartialStackFrame(package: 'package:flutter/src/widgets/framework.dart', className: 'StatefulElement', method: 'performRebuild');
288 289 290 291 292 293 294 295 296 297

    const String replacementString = '...     Normal element mounting';

    // ComponentElement variations
    FlutterError.addDefaultStackFilter(const RepetitiveStackFrameFilter(
      frames: <PartialStackFrame>[
        elementInflateWidget,
        elementUpdateChild,
        componentElementPerformRebuild,
        elementRebuild,
Dan Field's avatar
Dan Field committed
298
        componentElementFirstBuild,
299 300 301 302 303 304 305 306 307
        componentElementMount,
      ],
      replacement: replacementString,
    ));
    FlutterError.addDefaultStackFilter(const RepetitiveStackFrameFilter(
      frames: <PartialStackFrame>[
        elementUpdateChild,
        componentElementPerformRebuild,
        elementRebuild,
Dan Field's avatar
Dan Field committed
308
        componentElementFirstBuild,
309 310 311 312 313 314 315 316 317 318 319
        componentElementMount,
      ],
      replacement: replacementString,
    ));

    // StatefulElement variations
    FlutterError.addDefaultStackFilter(const RepetitiveStackFrameFilter(
      frames: <PartialStackFrame>[
        elementInflateWidget,
        elementUpdateChild,
        componentElementPerformRebuild,
Dan Field's avatar
Dan Field committed
320
        statefulElementRebuild,
321
        elementRebuild,
Dan Field's avatar
Dan Field committed
322 323
        componentElementFirstBuild,
        statefulElementFirstBuild,
324 325 326 327 328 329 330 331
        componentElementMount,
      ],
      replacement: replacementString,
    ));
    FlutterError.addDefaultStackFilter(const RepetitiveStackFrameFilter(
      frames: <PartialStackFrame>[
        elementUpdateChild,
        componentElementPerformRebuild,
Dan Field's avatar
Dan Field committed
332
        statefulElementRebuild,
333
        elementRebuild,
Dan Field's avatar
Dan Field committed
334 335
        componentElementFirstBuild,
        statefulElementFirstBuild,
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
        componentElementMount,
      ],
      replacement: replacementString,
    ));

    // SingleChildRenderObjectElement variations
    FlutterError.addDefaultStackFilter(const RepetitiveStackFrameFilter(
      frames: <PartialStackFrame>[
        elementInflateWidget,
        elementUpdateChild,
        singleChildMount,
      ],
      replacement: replacementString,
    ));
    FlutterError.addDefaultStackFilter(const RepetitiveStackFrameFilter(
      frames: <PartialStackFrame>[
        elementUpdateChild,
        singleChildMount,
      ],
      replacement: replacementString,
    ));
  }

359 360 361 362
  @override
  void initServiceExtensions() {
    super.initServiceExtensions();

363
    if (!kReleaseMode) {
364
      registerServiceExtension(
365
        name: WidgetsServiceExtensions.debugDumpApp.name,
366 367 368 369 370
        callback: (Map<String, String> parameters) async {
          final String data = _debugDumpAppString();
          return <String, Object>{
            'data': data,
          };
371 372
        },
      );
373

374 375
      if (!kIsWeb) {
        registerBoolServiceExtension(
376
          name: WidgetsServiceExtensions.showPerformanceOverlay.name,
377 378 379
          getter: () =>
          Future<bool>.value(WidgetsApp.showPerformanceOverlayOverride),
          setter: (bool value) {
380
            if (WidgetsApp.showPerformanceOverlayOverride == value) {
381
              return Future<void>.value();
382
            }
383 384 385 386 387
            WidgetsApp.showPerformanceOverlayOverride = value;
            return _forceRebuild();
          },
        );
      }
388 389

      registerServiceExtension(
390
        name: WidgetsServiceExtensions.didSendFirstFrameEvent.name,
391 392
        callback: (_) async {
          return <String, dynamic>{
393 394 395
            // This is defined to return a STRING, not a boolean.
            // Devtools, the Intellij plugin, and the flutter tool all depend
            // on it returning a string and not a boolean.
396
            'enabled': _needToReportFirstFrame ? 'false' : 'true',
397 398 399
          };
        },
      );
400

401
      registerServiceExtension(
402
        name: WidgetsServiceExtensions.didSendFirstFrameRasterizedEvent.name,
403 404 405 406 407 408 409 410 411 412
        callback: (_) async {
          return <String, dynamic>{
            // This is defined to return a STRING, not a boolean.
            // Devtools, the Intellij plugin, and the flutter tool all depend
            // on it returning a string and not a boolean.
            'enabled': firstFrameRasterized ? 'true' : 'false',
          };
        },
      );

413
      registerServiceExtension(
414
        name: WidgetsServiceExtensions.fastReassemble.name,
415
        callback: (Map<String, Object> params) async {
416 417 418 419 420 421 422 423 424 425
          // This mirrors the implementation of the 'reassemble' callback registration
          // in lib/src/foundation/binding.dart, but with the extra binding config used
          // to skip some reassemble work.
          final String? className = params['className'] as String?;
          BindingBase.debugReassembleConfig = DebugReassembleConfig(widgetName: className);
          try {
            await reassembleApplication();
          } finally {
            BindingBase.debugReassembleConfig = null;
          }
426
          return <String, String>{'type': 'Success'};
427 428 429
        },
      );

430 431
      // Expose the ability to send Widget rebuilds as [Timeline] events.
      registerBoolServiceExtension(
432
        name: WidgetsServiceExtensions.profileWidgetBuilds.name,
433 434
        getter: () async => debugProfileBuildsEnabled,
        setter: (bool value) async {
435 436
          debugProfileBuildsEnabled = value;
        }
437
      );
438
      registerBoolServiceExtension(
439
        name: WidgetsServiceExtensions.profileUserWidgetBuilds.name,
440 441
        getter: () async => debugProfileBuildsEnabledUserWidgets,
        setter: (bool value) async {
442 443
          debugProfileBuildsEnabledUserWidgets = value;
        }
444
      );
445
    }
446

447
    assert(() {
448
      registerBoolServiceExtension(
449
        name: WidgetsServiceExtensions.debugAllowBanner.name,
450 451
        getter: () => Future<bool>.value(WidgetsApp.debugAllowBannerOverride),
        setter: (bool value) {
452
          if (WidgetsApp.debugAllowBannerOverride == value) {
453
            return Future<void>.value();
454
          }
455 456 457 458 459 460 461 462 463
          WidgetsApp.debugAllowBannerOverride = value;
          return _forceRebuild();
        },
      );

      WidgetInspectorService.instance.initServiceExtensions(registerServiceExtension);

      return true;
    }());
464 465
  }

466
  Future<void> _forceRebuild() {
467
    if (renderViewElement != null) {
468
      buildOwner!.reassemble(renderViewElement!, null);
469 470
      return endOfFrame;
    }
471
    return Future<void>.value();
472 473
  }

474 475
  /// The [BuildOwner] in charge of executing the build pipeline for the
  /// widget tree rooted at this binding.
476
  BuildOwner? get buildOwner => _buildOwner;
477 478 479
  // Initialization of [_buildOwner] has to be done within the [initInstances]
  // method, as it requires [ServicesBinding] to properly setup the
  // [defaultBinaryMessenger] instance.
480
  BuildOwner? _buildOwner;
Ian Hickson's avatar
Ian Hickson committed
481

482
  /// The object in charge of the focus tree.
483
  ///
484 485
  /// Rarely used directly. Instead, consider using [FocusScope.of] to obtain
  /// the [FocusScopeNode] for a given [BuildContext].
486
  ///
487
  /// See [FocusManager] for more details.
488
  FocusManager get focusManager => _buildOwner!.focusManager;
489

490 491 492 493 494 495 496
  /// A delegate that communicates with a platform plugin for serializing and
  /// managing platform-rendered menu bars created by [PlatformMenuBar].
  ///
  /// This is set by default to a [DefaultPlatformMenuDelegate] instance in
  /// [initInstances].
  late PlatformMenuDelegate platformMenuDelegate;

497
  final List<WidgetsBindingObserver> _observers = <WidgetsBindingObserver>[];
Ian Hickson's avatar
Ian Hickson committed
498

499 500 501 502 503 504 505 506 507 508 509 510
  /// Registers the given object as a binding observer. Binding
  /// observers are notified when various application events occur,
  /// for example when the system locale changes. Generally, one
  /// widget in the widget tree registers itself as a binding
  /// observer, and converts the system state into inherited widgets.
  ///
  /// For example, the [WidgetsApp] widget registers as a binding
  /// observer and passes the screen size to a [MediaQuery] widget
  /// each time it is built, which enables other widgets to use the
  /// [MediaQuery.of] static method and (implicitly) the
  /// [InheritedWidget] mechanism to be notified whenever the screen
  /// size changes (e.g. whenever the screen rotates).
511 512 513 514 515
  ///
  /// See also:
  ///
  ///  * [removeObserver], to release the resources reserved by this method.
  ///  * [WidgetsBindingObserver], which has an example of using this method.
516 517 518 519 520
  void addObserver(WidgetsBindingObserver observer) => _observers.add(observer);

  /// Unregisters the given observer. This should be used sparingly as
  /// it is relatively expensive (O(N) in the number of registered
  /// observers).
521 522 523 524 525
  ///
  /// See also:
  ///
  ///  * [addObserver], for the method that adds observers in the first place.
  ///  * [WidgetsBindingObserver], which has an example of using this method.
526 527
  bool removeObserver(WidgetsBindingObserver observer) => _observers.remove(observer);

528
  @override
Ian Hickson's avatar
Ian Hickson committed
529 530
  void handleMetricsChanged() {
    super.handleMetricsChanged();
531
    for (final WidgetsBindingObserver observer in _observers) {
532
      observer.didChangeMetrics();
533
    }
Ian Hickson's avatar
Ian Hickson committed
534 535
  }

536 537 538
  @override
  void handleTextScaleFactorChanged() {
    super.handleTextScaleFactorChanged();
539
    for (final WidgetsBindingObserver observer in _observers) {
540
      observer.didChangeTextScaleFactor();
541
    }
542 543
  }

544 545 546
  @override
  void handlePlatformBrightnessChanged() {
    super.handlePlatformBrightnessChanged();
547
    for (final WidgetsBindingObserver observer in _observers) {
548
      observer.didChangePlatformBrightness();
549
    }
550 551
  }

552 553 554
  @override
  void handleAccessibilityFeaturesChanged() {
    super.handleAccessibilityFeaturesChanged();
555
    for (final WidgetsBindingObserver observer in _observers) {
556
      observer.didChangeAccessibilityFeatures();
557
    }
558 559
  }

560
  /// Called when the system locale changes.
561
  ///
562
  /// Calls [dispatchLocalesChanged] to notify the binding observers.
563
  ///
564
  /// See [dart:ui.PlatformDispatcher.onLocaleChanged].
565 566
  @protected
  @mustCallSuper
Ian Hickson's avatar
Ian Hickson committed
567
  void handleLocaleChanged() {
568
    dispatchLocalesChanged(platformDispatcher.locales);
Ian Hickson's avatar
Ian Hickson committed
569 570
  }

571
  /// Notify all the observers that the locale has changed (using
572 573
  /// [WidgetsBindingObserver.didChangeLocales]), giving them the
  /// `locales` argument.
574
  ///
575 576
  /// This is called by [handleLocaleChanged] when the
  /// [PlatformDispatcher.onLocaleChanged] notification is received.
577 578
  @protected
  @mustCallSuper
579
  void dispatchLocalesChanged(List<Locale>? locales) {
580
    for (final WidgetsBindingObserver observer in _observers) {
581
      observer.didChangeLocales(locales);
582
    }
Ian Hickson's avatar
Ian Hickson committed
583 584
  }

585 586 587 588 589
  /// Notify all the observers that the active set of [AccessibilityFeatures]
  /// has changed (using [WidgetsBindingObserver.didChangeAccessibilityFeatures]),
  /// giving them the `features` argument.
  ///
  /// This is called by [handleAccessibilityFeaturesChanged] when the
590
  /// [PlatformDispatcher.onAccessibilityFeaturesChanged] notification is received.
591 592 593
  @protected
  @mustCallSuper
  void dispatchAccessibilityFeaturesChanged() {
594
    for (final WidgetsBindingObserver observer in _observers) {
595
      observer.didChangeAccessibilityFeatures();
596
    }
597 598
  }

599
  /// Called when the system pops the current route.
600 601
  ///
  /// This first notifies the binding observers (using
602 603 604 605
  /// [WidgetsBindingObserver.didPopRoute]), in registration order, until one
  /// returns true, meaning that it was able to handle the request (e.g. by
  /// closing a dialog box). If none return true, then the application is shut
  /// down by calling [SystemNavigator.pop].
606 607 608 609
  ///
  /// [WidgetsApp] uses this in conjunction with a [Navigator] to
  /// cause the back button to close dialog boxes, return from modal
  /// pages, and so forth.
610 611 612
  ///
  /// This method exposes the `popRoute` notification from
  /// [SystemChannels.navigation].
613
  @protected
614
  Future<void> handlePopRoute() async {
615
    for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
616
      if (await observer.didPopRoute()) {
617
        return;
618
      }
Ian Hickson's avatar
Ian Hickson committed
619
    }
620
    SystemNavigator.pop();
Ian Hickson's avatar
Ian Hickson committed
621
  }
Hixie's avatar
Hixie committed
622

623 624
  /// Called when the host tells the app to push a new route onto the
  /// navigator.
625 626 627 628 629 630 631 632
  ///
  /// This notifies the binding observers (using
  /// [WidgetsBindingObserver.didPushRoute]), in registration order, until one
  /// returns true, meaning that it was able to handle the request (e.g. by
  /// opening a dialog box). If none return true, then nothing happens.
  ///
  /// This method exposes the `pushRoute` notification from
  /// [SystemChannels.navigation].
633 634
  @protected
  @mustCallSuper
635
  Future<void> handlePushRoute(String route) async {
636
    for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
637
      if (await observer.didPushRoute(route)) {
638
        return;
639
      }
640 641 642
    }
  }

643
  Future<void> _handlePushRouteInformation(Map<dynamic, dynamic> routeArguments) async {
644
    for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
645 646 647 648
      if (
        await observer.didPushRouteInformation(
          RouteInformation(
            location: routeArguments['location'] as String,
649
            state: routeArguments['state'] as Object?,
650
          ),
651
        )
652 653 654
      ) {
        return;
      }
655 656 657
    }
  }

658 659 660 661 662
  Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
    switch (methodCall.method) {
      case 'popRoute':
        return handlePopRoute();
      case 'pushRoute':
663
        return handlePushRoute(methodCall.arguments as String);
664 665
      case 'pushRouteInformation':
        return _handlePushRouteInformation(methodCall.arguments as Map<dynamic, dynamic>);
666
    }
667
    return Future<dynamic>.value();
668 669
  }

670
  @override
671
  void handleAppLifecycleStateChanged(AppLifecycleState state) {
672
    super.handleAppLifecycleStateChanged(state);
673
    for (final WidgetsBindingObserver observer in _observers) {
674
      observer.didChangeAppLifecycleState(state);
675
    }
676 677
  }

678
  @override
679
  void handleMemoryPressure() {
680
    super.handleMemoryPressure();
681
    for (final WidgetsBindingObserver observer in _observers) {
682
      observer.didHaveMemoryPressure();
683
    }
684 685
  }

686
  bool _needToReportFirstFrame = true;
687 688 689 690 691

  final Completer<void> _firstFrameCompleter = Completer<void>();

  /// Whether the Flutter engine has rasterized the first frame.
  ///
692 693 694
  /// Usually, the time that a frame is rasterized is very close to the time that
  /// it gets presented on the display. Specifically, rasterization is the last
  /// expensive phase of a frame that's still in Flutter's control.
695 696 697 698 699 700 701 702 703 704
  ///
  /// See also:
  ///
  ///  * [waitUntilFirstFrameRasterized], the future when [firstFrameRasterized]
  ///    becomes true.
  bool get firstFrameRasterized => _firstFrameCompleter.isCompleted;

  /// A future that completes when the Flutter engine has rasterized the first
  /// frame.
  ///
705 706 707
  /// Usually, the time that a frame is rasterized is very close to the time that
  /// it gets presented on the display. Specifically, rasterization is the last
  /// expensive phase of a frame that's still in Flutter's control.
708 709 710 711 712 713 714
  ///
  /// See also:
  ///
  ///  * [firstFrameRasterized], whether this future has completed or not.
  Future<void> get waitUntilFirstFrameRasterized => _firstFrameCompleter.future;

  /// Whether the first frame has finished building.
715
  ///
716 717
  /// This value can also be obtained over the VM service protocol as
  /// `ext.flutter.didSendFirstFrameEvent`.
718 719 720 721
  ///
  /// See also:
  ///
  ///  * [firstFrameRasterized], whether the first frame has finished rendering.
722 723
  bool get debugDidSendFirstFrameEvent => !_needToReportFirstFrame;

724
  void _handleBuildScheduled() {
725 726 727 728
    // If we're in the process of building dirty elements, then changes
    // should not trigger a new frame.
    assert(() {
      if (debugBuildingDirtyElements) {
729 730 731 732
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('Build scheduled during frame.'),
          ErrorDescription(
            'While the widget tree was being built, laid out, and painted, '
733
            'a new frame was scheduled to rebuild the widget tree.',
734 735 736 737 738 739 740 741 742 743 744 745 746 747
          ),
          ErrorHint(
            'This might be because setState() was called from a layout or '
            'paint callback. '
            'If a change is needed to the widget tree, it should be applied '
            'as the tree is being built. Scheduling a change for the subsequent '
            'frame instead results in an interface that lags behind by one frame. '
            'If this was done to make your build dependent on a size measured at '
            'layout time, consider using a LayoutBuilder, CustomSingleChildLayout, '
            'or CustomMultiChildLayout. If, on the other hand, the one frame delay '
            'is the desired effect, for example because this is an '
            'animation, consider scheduling the frame in a post-frame callback '
            'using SchedulerBinding.addPostFrameCallback or '
            'using an AnimationController to trigger the animation.',
748
          ),
749
        ]);
750 751
      }
      return true;
752
    }());
753
    ensureVisualUpdate();
754 755
  }

756 757 758 759 760 761 762 763
  /// Whether we are currently in a frame. This is used to verify
  /// that frames are not scheduled redundantly.
  ///
  /// This is public so that test frameworks can change it.
  ///
  /// This flag is not used in release builds.
  @protected
  bool debugBuildingDirtyElements = false;
764

765 766
  /// Pump the build and rendering pipeline to generate a frame.
  ///
767
  /// This method is called by [handleDrawFrame], which itself is called
Wu Zhong's avatar
Wu Zhong committed
768
  /// automatically by the engine when it is time to lay out and paint a
769 770 771 772 773
  /// frame.
  ///
  /// Each frame consists of the following phases:
  ///
  /// 1. The animation phase: The [handleBeginFrame] method, which is registered
774 775 776 777 778
  /// with [PlatformDispatcher.onBeginFrame], invokes all the transient frame
  /// callbacks registered with [scheduleFrameCallback], in registration order.
  /// This includes all the [Ticker] instances that are driving
  /// [AnimationController] objects, which means all of the active [Animation]
  /// objects tick at this point.
779
  ///
780 781 782 783
  /// 2. Microtasks: After [handleBeginFrame] returns, any microtasks that got
  /// scheduled by transient frame callbacks get to run. This typically includes
  /// callbacks for futures from [Ticker]s and [AnimationController]s that
  /// completed this frame.
784
  ///
785
  /// After [handleBeginFrame], [handleDrawFrame], which is registered with
786 787 788
  /// [PlatformDispatcher.onDrawFrame], is called, which invokes all the
  /// persistent frame callbacks, of which the most notable is this method,
  /// [drawFrame], which proceeds as follows:
789 790
  ///
  /// 3. The build phase: All the dirty [Element]s in the widget tree are
791 792 793 794
  /// rebuilt (see [State.build]). See [State.setState] for further details on
  /// marking a widget dirty for building. See [BuildOwner] for more information
  /// on this step.
  ///
795
  /// 4. The layout phase: All the dirty [RenderObject]s in the system are laid
796 797 798
  /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
  /// for further details on marking an object dirty for layout.
  ///
799
  /// 5. The compositing bits phase: The compositing bits on any dirty
800 801 802
  /// [RenderObject] objects are updated. See
  /// [RenderObject.markNeedsCompositingBitsUpdate].
  ///
803
  /// 6. The paint phase: All the dirty [RenderObject]s in the system are
804 805 806 807
  /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
  /// [RenderObject.markNeedsPaint] for further details on marking an object
  /// dirty for paint.
  ///
808
  /// 7. The compositing phase: The layer tree is turned into a [Scene] and
809 810
  /// sent to the GPU.
  ///
811
  /// 8. The semantics phase: All the dirty [RenderObject]s in the system have
812
  /// their semantics updated (see [RenderObject.assembleSemanticsNode]). This
813 814 815 816
  /// generates the [SemanticsNode] tree. See
  /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
  /// object dirty for semantics.
  ///
817
  /// For more details on steps 4-8, see [PipelineOwner].
818
  ///
819
  /// 9. The finalization phase in the widgets layer: The widgets tree is
820 821 822 823
  /// finalized. This causes [State.dispose] to be invoked on any objects that
  /// were removed from the widgets tree this frame. See
  /// [BuildOwner.finalizeTree] for more details.
  ///
824 825 826
  /// 10. The finalization phase in the scheduler layer: After [drawFrame]
  /// returns, [handleDrawFrame] then invokes post-frame callbacks (registered
  /// with [addPostFrameCallback]).
827 828
  //
  // When editing the above, also update rendering/binding.dart's copy.
829
  @override
830
  void drawFrame() {
831 832 833 834
    assert(!debugBuildingDirtyElements);
    assert(() {
      debugBuildingDirtyElements = true;
      return true;
835
    }());
836

837
    TimingsCallback? firstFrameCallback;
838
    if (_needToReportFirstFrame) {
839
      assert(!_firstFrameCompleter.isCompleted);
840 841

      firstFrameCallback = (List<FrameTiming> timings) {
842
        assert(sendFramesToEngine);
843
        if (!kReleaseMode) {
844 845 846 847 848
          // Change the current user tag back to the default tag. At this point,
          // the user tag should be set to "AppStartUp" (originally set in the
          // engine), so we need to change it back to the default tag to mark
          // the end of app start up for CPU profiles.
          developer.UserTag.defaultTag.makeCurrent();
849 850 851
          developer.Timeline.instantSync('Rasterized first useful frame');
          developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
        }
852
        SchedulerBinding.instance.removeTimingsCallback(firstFrameCallback!);
853
        firstFrameCallback = null;
854
        _firstFrameCompleter.complete();
855
      };
856 857 858
      // Callback is only invoked when FlutterView.render is called. When
      // sendFramesToEngine is set to false during the frame, it will not be
      // called and we need to remove the callback (see below).
859
      SchedulerBinding.instance.addTimingsCallback(firstFrameCallback!);
860 861
    }

862
    try {
863
      if (renderViewElement != null) {
864
        buildOwner!.buildScope(renderViewElement!);
865
      }
866
      super.drawFrame();
867
      buildOwner!.finalizeTree();
868 869 870 871
    } finally {
      assert(() {
        debugBuildingDirtyElements = false;
        return true;
872
      }());
873
    }
874
    if (!kReleaseMode) {
875
      if (_needToReportFirstFrame && sendFramesToEngine) {
876
        developer.Timeline.instantSync('Widgets built first useful frame');
877
      }
878
    }
879
    _needToReportFirstFrame = false;
880
    if (firstFrameCallback != null && !sendFramesToEngine) {
881 882 883
      // This frame is deferred and not the first frame sent to the engine that
      // should be reported.
      _needToReportFirstFrame = true;
884
      SchedulerBinding.instance.removeTimingsCallback(firstFrameCallback!);
885
    }
886
  }
887 888 889

  /// The [Element] that is at the root of the hierarchy (and which wraps the
  /// [RenderView] object at the root of the rendering hierarchy).
890 891
  ///
  /// This is initialized the first time [runApp] is called.
892 893
  Element? get renderViewElement => _renderViewElement;
  Element? _renderViewElement;
894

895 896 897 898 899
  bool _readyToProduceFrames = false;

  @override
  bool get framesEnabled => super.framesEnabled && _readyToProduceFrames;

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
  /// Used by [runApp] to wrap the provided `rootWidget` in the default [View].
  ///
  /// The [View] determines into what [FlutterView] the app is rendered into.
  /// For backwards-compatibility reasons, this method currently chooses
  /// [window] (which is a [FlutterView]) as the rendering target. This will
  /// change in a future version of Flutter.
  ///
  /// The `rootWidget` widget provided to this method must not already be
  /// wrapped in a [View].
  Widget wrapWithDefaultView(Widget rootWidget) {
    return View(
      view: window,
      child: rootWidget,
    );
  }

916 917 918 919 920 921 922 923 924 925 926
  /// Schedules a [Timer] for attaching the root widget.
  ///
  /// This is called by [runApp] to configure the widget tree. Consider using
  /// [attachRootWidget] if you want to build the widget tree synchronously.
  @protected
  void scheduleAttachRootWidget(Widget rootWidget) {
    Timer.run(() {
      attachRootWidget(rootWidget);
    });
  }

927 928 929 930 931
  /// Takes a widget and attaches it to the [renderViewElement], creating it if
  /// necessary.
  ///
  /// This is called by [runApp] to configure the widget tree.
  ///
932 933 934 935
  /// See also:
  ///
  ///  * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a
  ///    widget and attaches it to the render tree.
936
  void attachRootWidget(Widget rootWidget) {
937
    final bool isBootstrapFrame = renderViewElement == null;
938
    _readyToProduceFrames = true;
939
    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
940
      container: renderView,
941
      debugShortDescription: '[root]',
942
      child: rootWidget,
943
    ).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
944
    if (isBootstrapFrame) {
945
      SchedulerBinding.instance.ensureVisualUpdate();
946
    }
947
  }
948

949 950 951 952 953 954
  /// Whether the [renderViewElement] has been initialized.
  ///
  /// This will be false until [runApp] is called (or [WidgetTester.pumpWidget]
  /// is called in the context of a [TestWidgetsFlutterBinding]).
  bool get isRootWidgetAttached => _renderViewElement != null;

955
  @override
956
  Future<void> performReassemble() {
957 958 959 960 961
    assert(() {
      WidgetInspectorService.instance.performReassemble();
      return true;
    }());

962
    if (renderViewElement != null) {
963
      buildOwner!.reassemble(renderViewElement!, BindingBase.debugReassembleConfig);
964
    }
965
    return super.performReassemble();
966
  }
967 968 969

  /// Computes the locale the current platform would resolve to.
  ///
970 971 972 973 974
  /// This method is meant to be used as part of a
  /// [WidgetsApp.localeListResolutionCallback]. Since this method may return
  /// null, a Flutter/dart algorithm should still be provided as a fallback in
  /// case a native resolved locale cannot be determined or if the native
  /// resolved locale is undesirable.
975 976 977 978
  ///
  /// This method may return a null [Locale] if the platform does not support
  /// native locale resolution, or if the resolution failed.
  ///
979
  /// The first `supportedLocale` is treated as the default locale and will be returned
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
  /// if no better match is found.
  ///
  /// Android and iOS are currently supported.
  ///
  /// On Android, the algorithm described in
  /// https://developer.android.com/guide/topics/resources/multilingual-support
  /// is used to determine the resolved locale. Depending on the android version
  /// of the device, either the modern (>= API 24) or legacy (< API 24) algorithm
  /// will be used.
  ///
  /// On iOS, the result of `preferredLocalizationsFromArray` method of `NSBundle`
  /// is returned. See:
  /// https://developer.apple.com/documentation/foundation/nsbundle/1417249-preferredlocalizationsfromarray?language=objc
  /// for details on the used method.
  ///
  /// iOS treats script code as necessary for a match, so a user preferred locale of
  /// `zh_Hans_CN` will not resolve to a supported locale of `zh_CN`.
  ///
  /// Since implementation may vary by platform and has potential to be heavy,
  /// it is recommended to cache the results of this method if the value is
  /// used multiple times.
  ///
  /// Second-best (and n-best) matching locales should be obtained by calling this
  /// method again with the matched locale of the first call omitted from
1004
  /// `supportedLocales`.
1005
  Locale? computePlatformResolvedLocale(List<Locale> supportedLocales) {
1006
    return platformDispatcher.computePlatformResolvedLocale(supportedLocales);
1007
  }
1008
}
Hixie's avatar
Hixie committed
1009

1010
/// Inflate the given widget and attach it to the screen.
1011
///
1012 1013 1014
/// The widget is given constraints during layout that force it to fill the
/// entire screen. If you wish to align your widget to one side of the screen
/// (e.g., the top), consider using the [Align] widget. If you wish to center
1015
/// your widget, you can also use the [Center] widget.
1016
///
1017 1018 1019 1020 1021 1022
/// Calling [runApp] again will detach the previous root widget from the screen
/// and attach the given widget in its place. The new widget tree is compared
/// against the previous widget tree and any differences are applied to the
/// underlying render tree, similar to what happens when a [StatefulWidget]
/// rebuilds after calling [State.setState].
///
1023
/// Initializes the binding using [WidgetsFlutterBinding] if necessary.
1024 1025 1026
///
/// See also:
///
1027 1028 1029 1030 1031 1032
///  * [WidgetsBinding.attachRootWidget], which creates the root widget for the
///    widget hierarchy.
///  * [RenderObjectToWidgetAdapter.attachToRenderTree], which creates the root
///    element for the element hierarchy.
///  * [WidgetsBinding.handleBeginFrame], which pumps the widget pipeline to
///    ensure the widget, element, and render trees are all built.
Hixie's avatar
Hixie committed
1033
void runApp(Widget app) {
1034 1035 1036
  final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
  binding
    ..scheduleAttachRootWidget(binding.wrapWithDefaultView(app))
1037
    ..scheduleWarmUpFrame();
Hixie's avatar
Hixie committed
1038 1039
}

1040
String _debugDumpAppString() {
1041
  const String mode = kDebugMode ? 'DEBUG MODE' : kReleaseMode ? 'RELEASE MODE' : 'PROFILE MODE';
1042 1043
  final StringBuffer buffer = StringBuffer();
  buffer.writeln('${WidgetsBinding.instance.runtimeType} - $mode');
1044 1045
  if (WidgetsBinding.instance.renderViewElement != null) {
    buffer.writeln(WidgetsBinding.instance.renderViewElement!.toStringDeep());
1046
  } else {
1047
    buffer.writeln('<no tree currently mounted>');
1048
  }
1049 1050 1051 1052 1053
  return buffer.toString();
}

/// Print a string representation of the currently running app.
void debugDumpApp() {
1054
  debugPrint(_debugDumpAppString());
1055 1056
}

1057 1058 1059 1060 1061 1062 1063 1064
/// A bridge from a [RenderObject] to an [Element] tree.
///
/// The given container is the [RenderObject] that the [Element] tree should be
/// inserted into. It must be a [RenderObject] that implements the
/// [RenderObjectWithChildMixin] protocol. The type argument `T` is the kind of
/// [RenderObject] that the container expects as its child.
///
/// Used by [runApp] to bootstrap applications.
Hixie's avatar
Hixie committed
1065
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
1066 1067 1068
  /// Creates a bridge from a [RenderObject] to an [Element] tree.
  ///
  /// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
1069 1070
  RenderObjectToWidgetAdapter({
    this.child,
1071
    required this.container,
1072
    this.debugShortDescription,
1073
  }) : super(key: GlobalObjectKey(container));
Hixie's avatar
Hixie committed
1074

1075
  /// The widget below this widget in the tree.
1076
  ///
1077
  /// {@macro flutter.widgets.ProxyWidget.child}
1078
  final Widget? child;
1079

1080
  /// The [RenderObject] that is the parent of the [Element] created by this widget.
Hixie's avatar
Hixie committed
1081
  final RenderObjectWithChildMixin<T> container;
1082

1083
  /// A short description of this widget used by debugging aids.
1084
  final String? debugShortDescription;
Hixie's avatar
Hixie committed
1085

1086
  @override
1087
  RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
Hixie's avatar
Hixie committed
1088

1089
  @override
1090
  RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;
Hixie's avatar
Hixie committed
1091

1092
  @override
1093
  void updateRenderObject(BuildContext context, RenderObject renderObject) { }
1094

1095 1096
  /// Inflate this widget and actually set the resulting [RenderObject] as the
  /// child of [container].
1097 1098
  ///
  /// If `element` is null, this function will create a new element. Otherwise,
1099
  /// the given element will have an update scheduled to switch to this widget.
1100 1101
  ///
  /// Used by [runApp] to bootstrap applications.
1102
  RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {
1103 1104
    if (element == null) {
      owner.lockState(() {
1105
        element = createElement();
1106
        assert(element != null);
1107
        element!.assignOwner(owner);
1108
      });
1109 1110
      owner.buildScope(element!, () {
        element!.mount(null, null);
1111 1112
      });
    } else {
1113 1114
      element._newWidget = this;
      element.markNeedsBuild();
1115
    }
1116
    return element!;
1117
  }
1118

1119
  @override
1120
  String toStringShort() => debugShortDescription ?? super.toStringShort();
Hixie's avatar
Hixie committed
1121 1122
}

1123 1124 1125 1126 1127
/// A [RootRenderObjectElement] that is hosted by a [RenderObject].
///
/// This element class is the instantiation of a [RenderObjectToWidgetAdapter]
/// widget. It can be used only as the root of an [Element] tree (it cannot be
/// mounted into another [Element]; it's parent must be null).
Hixie's avatar
Hixie committed
1128
///
1129 1130
/// In typical usage, it will be instantiated for a [RenderObjectToWidgetAdapter]
/// whose container is the [RenderView] that connects to the Flutter engine. In
Hixie's avatar
Hixie committed
1131
/// this usage, it is normally instantiated by the bootstrapping logic in the
1132
/// [WidgetsFlutterBinding] singleton created by [runApp].
1133
class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObjectElement {
1134 1135 1136 1137 1138
  /// Creates an element that is hosted by a [RenderObject].
  ///
  /// The [RenderObject] created by this element is not automatically set as a
  /// child of the hosting [RenderObject]. To actually attach this element to
  /// the render tree, call [RenderObjectToWidgetAdapter.attachToRenderTree].
1139
  RenderObjectToWidgetElement(RenderObjectToWidgetAdapter<T> super.widget);
Hixie's avatar
Hixie committed
1140

1141
  Element? _child;
Hixie's avatar
Hixie committed
1142

1143
  static const Object _rootChildSlot = Object();
Hixie's avatar
Hixie committed
1144

1145
  @override
Hixie's avatar
Hixie committed
1146
  void visitChildren(ElementVisitor visitor) {
1147
    if (_child != null) {
1148
      visitor(_child!);
1149
    }
Hixie's avatar
Hixie committed
1150 1151
  }

1152
  @override
1153
  void forgetChild(Element child) {
1154 1155
    assert(child == _child);
    _child = null;
1156
    super.forgetChild(child);
1157 1158
  }

1159
  @override
1160
  void mount(Element? parent, Object? newSlot) {
Hixie's avatar
Hixie committed
1161
    assert(parent == null);
Hixie's avatar
Hixie committed
1162
    super.mount(parent, newSlot);
1163
    _rebuild();
1164
    assert(_child != null);
Hixie's avatar
Hixie committed
1165 1166
  }

1167
  @override
Hixie's avatar
Hixie committed
1168 1169 1170
  void update(RenderObjectToWidgetAdapter<T> newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
1171 1172 1173
    _rebuild();
  }

1174 1175
  // When we are assigned a new widget, we store it here
  // until we are ready to update to it.
1176
  Widget? _newWidget;
1177 1178 1179

  @override
  void performRebuild() {
Ian Hickson's avatar
Ian Hickson committed
1180 1181 1182
    if (_newWidget != null) {
      // _newWidget can be null if, for instance, we were rebuilt
      // due to a reassemble.
1183
      final Widget newWidget = _newWidget!;
Ian Hickson's avatar
Ian Hickson committed
1184
      _newWidget = null;
1185
      update(newWidget as RenderObjectToWidgetAdapter<T>);
Ian Hickson's avatar
Ian Hickson committed
1186
    }
1187 1188 1189 1190
    super.performRebuild();
    assert(_newWidget == null);
  }

1191
  @pragma('vm:notify-debugger-on-exception')
1192 1193
  void _rebuild() {
    try {
1194
      _child = updateChild(_child, (widget as RenderObjectToWidgetAdapter<T>).child, _rootChildSlot);
1195
    } catch (exception, stack) {
1196
      final FlutterErrorDetails details = FlutterErrorDetails(
1197 1198 1199
        exception: exception,
        stack: stack,
        library: 'widgets library',
1200
        context: ErrorDescription('attaching to the render tree'),
1201 1202 1203
      );
      FlutterError.reportError(details);
      final Widget error = ErrorWidget.builder(details);
1204 1205
      _child = updateChild(null, error, _rootChildSlot);
    }
Hixie's avatar
Hixie committed
1206 1207
  }

1208
  @override
1209
  RenderObjectWithChildMixin<T> get renderObject => super.renderObject as RenderObjectWithChildMixin<T>;
Hixie's avatar
Hixie committed
1210

1211
  @override
1212
  void insertRenderObjectChild(RenderObject child, Object? slot) {
Ian Hickson's avatar
Ian Hickson committed
1213
    assert(slot == _rootChildSlot);
1214
    assert(renderObject.debugValidateChild(child));
1215
    renderObject.child = child as T;
Hixie's avatar
Hixie committed
1216 1217
  }

1218
  @override
1219
  void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) {
Adam Barth's avatar
Adam Barth committed
1220 1221 1222
    assert(false);
  }

1223
  @override
1224
  void removeRenderObjectChild(RenderObject child, Object? slot) {
Hixie's avatar
Hixie committed
1225 1226 1227
    assert(renderObject.child == child);
    renderObject.child = null;
  }
Adam Barth's avatar
Adam Barth committed
1228
}
1229 1230

/// A concrete binding for applications based on the Widgets framework.
1231
///
1232
/// This is the glue that binds the framework to the Flutter engine.
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
///
/// When using the widgets framework, this binding, or one that
/// implements the same interfaces, must be used. The following
/// mixins are used to implement this binding:
///
/// * [GestureBinding], which implements the basics of hit testing.
/// * [SchedulerBinding], which introduces the concepts of frames.
/// * [ServicesBinding], which provides access to the plugin subsystem.
/// * [PaintingBinding], which enables decoding images.
/// * [SemanticsBinding], which supports accessibility.
/// * [RendererBinding], which handles the render tree.
/// * [WidgetsBinding], which handles the widget tree.
1245
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
1246 1247 1248 1249
  /// Returns an instance of the binding that implements
  /// [WidgetsBinding]. If no binding has yet been initialized, the
  /// [WidgetsFlutterBinding] class is used to create and initialize
  /// one.
1250 1251 1252
  ///
  /// You only need to call this method if you need the binding to be
  /// initialized before calling [runApp].
1253 1254 1255
  ///
  /// In the `flutter_test` framework, [testWidgets] initializes the
  /// binding instance to a [TestWidgetsFlutterBinding], not a
1256 1257
  /// [WidgetsFlutterBinding]. See
  /// [TestWidgetsFlutterBinding.ensureInitialized].
1258
  static WidgetsBinding ensureInitialized() {
1259
    if (WidgetsBinding._instance == null) {
1260
      WidgetsFlutterBinding();
1261
    }
1262
    return WidgetsBinding.instance;
1263 1264
  }
}