• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:async';
6import 'dart:developer' as developer;
7import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures, FrameTiming, TimingsCallback;
8
9import 'package:flutter/foundation.dart';
10import 'package:flutter/gestures.dart';
11import 'package:flutter/rendering.dart';
12import 'package:flutter/scheduler.dart';
13import 'package:flutter/services.dart';
14
15import 'app.dart';
16import 'debug.dart';
17import 'focus_manager.dart';
18import 'framework.dart';
19import 'widget_inspector.dart';
20
21export 'dart:ui' show AppLifecycleState, Locale;
22
23/// Interface for classes that register with the Widgets layer binding.
24///
25/// When used as a mixin, provides no-op method implementations.
26///
27/// See [WidgetsBinding.addObserver] and [WidgetsBinding.removeObserver].
28///
29/// This class can be extended directly, to get default behaviors for all of the
30/// handlers, or can used with the `implements` keyword, in which case all the
31/// handlers must be implemented (and the analyzer will list those that have
32/// been omitted).
33///
34/// {@tool sample}
35///
36/// This [StatefulWidget] implements the parts of the [State] and
37/// [WidgetsBindingObserver] protocols necessary to react to application
38/// lifecycle messages. See [didChangeAppLifecycleState].
39///
40/// ```dart
41/// class AppLifecycleReactor extends StatefulWidget {
42///   const AppLifecycleReactor({ Key key }) : super(key: key);
43///
44///   @override
45///   _AppLifecycleReactorState createState() => _AppLifecycleReactorState();
46/// }
47///
48/// class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver {
49///   @override
50///   void initState() {
51///     super.initState();
52///     WidgetsBinding.instance.addObserver(this);
53///   }
54///
55///   @override
56///   void dispose() {
57///     WidgetsBinding.instance.removeObserver(this);
58///     super.dispose();
59///   }
60///
61///   AppLifecycleState _notification;
62///
63///   @override
64///   void didChangeAppLifecycleState(AppLifecycleState state) {
65///     setState(() { _notification = state; });
66///   }
67///
68///   @override
69///   Widget build(BuildContext context) {
70///     return Text('Last notification: $_notification');
71///   }
72/// }
73/// ```
74/// {@end-tool}
75///
76/// To respond to other notifications, replace the [didChangeAppLifecycleState]
77/// method above with other methods from this class.
78abstract class WidgetsBindingObserver {
79  /// Called when the system tells the app to pop the current route.
80  /// For example, on Android, this is called when the user presses
81  /// the back button.
82  ///
83  /// Observers are notified in registration order until one returns
84  /// true. If none return true, the application quits.
85  ///
86  /// Observers are expected to return true if they were able to
87  /// handle the notification, for example by closing an active dialog
88  /// box, and false otherwise. The [WidgetsApp] widget uses this
89  /// mechanism to notify the [Navigator] widget that it should pop
90  /// its current route if possible.
91  ///
92  /// This method exposes the `popRoute` notification from
93  /// [SystemChannels.navigation].
94  Future<bool> didPopRoute() => Future<bool>.value(false);
95
96  /// Called when the host tells the app to push a new route onto the
97  /// navigator.
98  ///
99  /// Observers are expected to return true if they were able to
100  /// handle the notification. Observers are notified in registration
101  /// order until one returns true.
102  ///
103  /// This method exposes the `pushRoute` notification from
104  /// [SystemChannels.navigation].
105  Future<bool> didPushRoute(String route) => Future<bool>.value(false);
106
107  /// Called when the application's dimensions change. For example,
108  /// when a phone is rotated.
109  ///
110  /// This method exposes notifications from [Window.onMetricsChanged].
111  ///
112  /// {@tool sample}
113  ///
114  /// This [StatefulWidget] implements the parts of the [State] and
115  /// [WidgetsBindingObserver] protocols necessary to react when the device is
116  /// rotated (or otherwise changes dimensions).
117  ///
118  /// ```dart
119  /// class MetricsReactor extends StatefulWidget {
120  ///   const MetricsReactor({ Key key }) : super(key: key);
121  ///
122  ///   @override
123  ///   _MetricsReactorState createState() => _MetricsReactorState();
124  /// }
125  ///
126  /// class _MetricsReactorState extends State<MetricsReactor> with WidgetsBindingObserver {
127  ///   @override
128  ///   void initState() {
129  ///     super.initState();
130  ///     WidgetsBinding.instance.addObserver(this);
131  ///   }
132  ///
133  ///   @override
134  ///   void dispose() {
135  ///     WidgetsBinding.instance.removeObserver(this);
136  ///     super.dispose();
137  ///   }
138  ///
139  ///   Size _lastSize;
140  ///
141  ///   @override
142  ///   void didChangeMetrics() {
143  ///     setState(() { _lastSize = WidgetsBinding.instance.window.physicalSize; });
144  ///   }
145  ///
146  ///   @override
147  ///   Widget build(BuildContext context) {
148  ///     return Text('Current size: $_lastSize');
149  ///   }
150  /// }
151  /// ```
152  /// {@end-tool}
153  ///
154  /// In general, this is unnecessary as the layout system takes care of
155  /// automatically recomputing the application geometry when the application
156  /// size changes.
157  ///
158  /// See also:
159  ///
160  ///  * [MediaQuery.of], which provides a similar service with less
161  ///    boilerplate.
162  void didChangeMetrics() { }
163
164  /// Called when the platform's text scale factor changes.
165  ///
166  /// This typically happens as the result of the user changing system
167  /// preferences, and it should affect all of the text sizes in the
168  /// application.
169  ///
170  /// This method exposes notifications from [Window.onTextScaleFactorChanged].
171  ///
172  /// {@tool sample}
173  ///
174  /// ```dart
175  /// class TextScaleFactorReactor extends StatefulWidget {
176  ///   const TextScaleFactorReactor({ Key key }) : super(key: key);
177  ///
178  ///   @override
179  ///   _TextScaleFactorReactorState createState() => _TextScaleFactorReactorState();
180  /// }
181  ///
182  /// class _TextScaleFactorReactorState extends State<TextScaleFactorReactor> with WidgetsBindingObserver {
183  ///   @override
184  ///   void initState() {
185  ///     super.initState();
186  ///     WidgetsBinding.instance.addObserver(this);
187  ///   }
188  ///
189  ///   @override
190  ///   void dispose() {
191  ///     WidgetsBinding.instance.removeObserver(this);
192  ///     super.dispose();
193  ///   }
194  ///
195  ///   double _lastTextScaleFactor;
196  ///
197  ///   @override
198  ///   void didChangeTextScaleFactor() {
199  ///     setState(() { _lastTextScaleFactor = WidgetsBinding.instance.window.textScaleFactor; });
200  ///   }
201  ///
202  ///   @override
203  ///   Widget build(BuildContext context) {
204  ///     return Text('Current scale factor: $_lastTextScaleFactor');
205  ///   }
206  /// }
207  /// ```
208  /// {@end-tool}
209  ///
210  /// See also:
211  ///
212  ///  * [MediaQuery.of], which provides a similar service with less
213  ///    boilerplate.
214  void didChangeTextScaleFactor() { }
215
216  /// {@macro on_platform_brightness_change}
217  void didChangePlatformBrightness() { }
218
219  /// Called when the system tells the app that the user's locale has
220  /// changed. For example, if the user changes the system language
221  /// settings.
222  ///
223  /// This method exposes notifications from [Window.onLocaleChanged].
224  void didChangeLocales(List<Locale> locale) { }
225
226  /// Called when the system puts the app in the background or returns
227  /// the app to the foreground.
228  ///
229  /// An example of implementing this method is provided in the class-level
230  /// documentation for the [WidgetsBindingObserver] class.
231  ///
232  /// This method exposes notifications from [SystemChannels.lifecycle].
233  void didChangeAppLifecycleState(AppLifecycleState state) { }
234
235  /// Called when the system is running low on memory.
236  ///
237  /// This method exposes the `memoryPressure` notification from
238  /// [SystemChannels.system].
239  void didHaveMemoryPressure() { }
240
241  /// Called when the system changes the set of currently active accessibility
242  /// features.
243  ///
244  /// This method exposes notifications from [Window.onAccessibilityFeaturesChanged].
245  void didChangeAccessibilityFeatures() { }
246}
247
248/// The glue between the widgets layer and the Flutter engine.
249mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
250  @override
251  void initInstances() {
252    super.initInstances();
253    _instance = this;
254    buildOwner.onBuildScheduled = _handleBuildScheduled;
255    window.onLocaleChanged = handleLocaleChanged;
256    window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
257    SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
258    SystemChannels.system.setMessageHandler(_handleSystemMessage);
259    FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
260  }
261
262  /// The current [WidgetsBinding], if one has been created.
263  ///
264  /// If you need the binding to be constructed before calling [runApp],
265  /// you can ensure a Widget binding has been constructed by calling the
266  /// `WidgetsFlutterBinding.ensureInitialized()` function.
267  static WidgetsBinding get instance => _instance;
268  static WidgetsBinding _instance;
269
270  @override
271  void initServiceExtensions() {
272    super.initServiceExtensions();
273
274    if (!kReleaseMode) {
275      registerSignalServiceExtension(
276        name: 'debugDumpApp',
277        callback: () {
278          debugDumpApp();
279          return debugPrintDone;
280        },
281      );
282
283      registerBoolServiceExtension(
284        name: 'showPerformanceOverlay',
285        getter: () =>
286        Future<bool>.value(WidgetsApp.showPerformanceOverlayOverride),
287        setter: (bool value) {
288          if (WidgetsApp.showPerformanceOverlayOverride == value)
289            return Future<void>.value();
290          WidgetsApp.showPerformanceOverlayOverride = value;
291          return _forceRebuild();
292        },
293      );
294
295      registerServiceExtension(
296        name: 'didSendFirstFrameEvent',
297        callback: (_) async {
298          return <String, dynamic>{
299            // This is defined to return a STRING, not a boolean.
300            // Devtools, the Intellij plugin, and the flutter tool all depend
301            // on it returning a string and not a boolean.
302            'enabled': _needToReportFirstFrame ? 'false' : 'true',
303          };
304        },
305      );
306
307      // This returns 'true' when the first frame is rasterized, and the trace
308      // event 'Rasterized first useful frame' is sent out.
309      registerServiceExtension(
310        name: 'didSendFirstFrameRasterizedEvent',
311        callback: (_) async {
312          return <String, dynamic>{
313            // This is defined to return a STRING, not a boolean.
314            // Devtools, the Intellij plugin, and the flutter tool all depend
315            // on it returning a string and not a boolean.
316            'enabled': firstFrameRasterized ? 'true' : 'false',
317          };
318        },
319      );
320
321      // Expose the ability to send Widget rebuilds as [Timeline] events.
322      registerBoolServiceExtension(
323        name: 'profileWidgetBuilds',
324        getter: () async => debugProfileBuildsEnabled,
325        setter: (bool value) async {
326          if (debugProfileBuildsEnabled != value)
327            debugProfileBuildsEnabled = value;
328        },
329      );
330    }
331
332    assert(() {
333      registerBoolServiceExtension(
334        name: 'debugAllowBanner',
335        getter: () => Future<bool>.value(WidgetsApp.debugAllowBannerOverride),
336        setter: (bool value) {
337          if (WidgetsApp.debugAllowBannerOverride == value)
338            return Future<void>.value();
339          WidgetsApp.debugAllowBannerOverride = value;
340          return _forceRebuild();
341        },
342      );
343
344      // This service extension is deprecated and will be removed by 12/1/2018.
345      // Use ext.flutter.inspector.show instead.
346      registerBoolServiceExtension(
347          name: 'debugWidgetInspector',
348          getter: () async => WidgetsApp.debugShowWidgetInspectorOverride,
349          setter: (bool value) {
350            if (WidgetsApp.debugShowWidgetInspectorOverride == value)
351              return Future<void>.value();
352            WidgetsApp.debugShowWidgetInspectorOverride = value;
353            return _forceRebuild();
354          },
355      );
356
357      WidgetInspectorService.instance.initServiceExtensions(registerServiceExtension);
358
359      return true;
360    }());
361  }
362
363  Future<void> _forceRebuild() {
364    if (renderViewElement != null) {
365      buildOwner.reassemble(renderViewElement);
366      return endOfFrame;
367    }
368    return Future<void>.value();
369  }
370
371  /// The [BuildOwner] in charge of executing the build pipeline for the
372  /// widget tree rooted at this binding.
373  BuildOwner get buildOwner => _buildOwner;
374  final BuildOwner _buildOwner = BuildOwner();
375
376  /// The object in charge of the focus tree.
377  ///
378  /// Rarely used directly. Instead, consider using [FocusScope.of] to obtain
379  /// the [FocusScopeNode] for a given [BuildContext].
380  ///
381  /// See [FocusManager] for more details.
382  FocusManager get focusManager => _buildOwner.focusManager;
383
384  final List<WidgetsBindingObserver> _observers = <WidgetsBindingObserver>[];
385
386  /// Registers the given object as a binding observer. Binding
387  /// observers are notified when various application events occur,
388  /// for example when the system locale changes. Generally, one
389  /// widget in the widget tree registers itself as a binding
390  /// observer, and converts the system state into inherited widgets.
391  ///
392  /// For example, the [WidgetsApp] widget registers as a binding
393  /// observer and passes the screen size to a [MediaQuery] widget
394  /// each time it is built, which enables other widgets to use the
395  /// [MediaQuery.of] static method and (implicitly) the
396  /// [InheritedWidget] mechanism to be notified whenever the screen
397  /// size changes (e.g. whenever the screen rotates).
398  ///
399  /// See also:
400  ///
401  ///  * [removeObserver], to release the resources reserved by this method.
402  ///  * [WidgetsBindingObserver], which has an example of using this method.
403  void addObserver(WidgetsBindingObserver observer) => _observers.add(observer);
404
405  /// Unregisters the given observer. This should be used sparingly as
406  /// it is relatively expensive (O(N) in the number of registered
407  /// observers).
408  ///
409  /// See also:
410  ///
411  ///  * [addObserver], for the method that adds observers in the first place.
412  ///  * [WidgetsBindingObserver], which has an example of using this method.
413  bool removeObserver(WidgetsBindingObserver observer) => _observers.remove(observer);
414
415  @override
416  void handleMetricsChanged() {
417    super.handleMetricsChanged();
418    for (WidgetsBindingObserver observer in _observers)
419      observer.didChangeMetrics();
420  }
421
422  @override
423  void handleTextScaleFactorChanged() {
424    super.handleTextScaleFactorChanged();
425    for (WidgetsBindingObserver observer in _observers)
426      observer.didChangeTextScaleFactor();
427  }
428
429  @override
430  void handlePlatformBrightnessChanged() {
431    super.handlePlatformBrightnessChanged();
432    for (WidgetsBindingObserver observer in _observers)
433      observer.didChangePlatformBrightness();
434  }
435
436  @override
437  void handleAccessibilityFeaturesChanged() {
438    super.handleAccessibilityFeaturesChanged();
439    for (WidgetsBindingObserver observer in _observers)
440      observer.didChangeAccessibilityFeatures();
441  }
442
443  /// Called when the system locale changes.
444  ///
445  /// Calls [dispatchLocaleChanged] to notify the binding observers.
446  ///
447  /// See [Window.onLocaleChanged].
448  @protected
449  @mustCallSuper
450  void handleLocaleChanged() {
451    dispatchLocalesChanged(window.locales);
452  }
453
454  /// Notify all the observers that the locale has changed (using
455  /// [WidgetsBindingObserver.didChangeLocales]), giving them the
456  /// `locales` argument.
457  ///
458  /// This is called by [handleLocaleChanged] when the [Window.onLocaleChanged]
459  /// notification is received.
460  @protected
461  @mustCallSuper
462  void dispatchLocalesChanged(List<Locale> locales) {
463    for (WidgetsBindingObserver observer in _observers)
464      observer.didChangeLocales(locales);
465  }
466
467  /// Notify all the observers that the active set of [AccessibilityFeatures]
468  /// has changed (using [WidgetsBindingObserver.didChangeAccessibilityFeatures]),
469  /// giving them the `features` argument.
470  ///
471  /// This is called by [handleAccessibilityFeaturesChanged] when the
472  /// [Window.onAccessibilityFeaturesChanged] notification is received.
473  @protected
474  @mustCallSuper
475  void dispatchAccessibilityFeaturesChanged() {
476    for (WidgetsBindingObserver observer in _observers)
477      observer.didChangeAccessibilityFeatures();
478  }
479
480  /// Called when the system pops the current route.
481  ///
482  /// This first notifies the binding observers (using
483  /// [WidgetsBindingObserver.didPopRoute]), in registration order, until one
484  /// returns true, meaning that it was able to handle the request (e.g. by
485  /// closing a dialog box). If none return true, then the application is shut
486  /// down by calling [SystemNavigator.pop].
487  ///
488  /// [WidgetsApp] uses this in conjunction with a [Navigator] to
489  /// cause the back button to close dialog boxes, return from modal
490  /// pages, and so forth.
491  ///
492  /// This method exposes the `popRoute` notification from
493  /// [SystemChannels.navigation].
494  @protected
495  Future<void> handlePopRoute() async {
496    for (WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
497      if (await observer.didPopRoute())
498        return;
499    }
500    SystemNavigator.pop();
501  }
502
503  /// Called when the host tells the app to push a new route onto the
504  /// navigator.
505  ///
506  /// This notifies the binding observers (using
507  /// [WidgetsBindingObserver.didPushRoute]), in registration order, until one
508  /// returns true, meaning that it was able to handle the request (e.g. by
509  /// opening a dialog box). If none return true, then nothing happens.
510  ///
511  /// This method exposes the `pushRoute` notification from
512  /// [SystemChannels.navigation].
513  @protected
514  @mustCallSuper
515  Future<void> handlePushRoute(String route) async {
516    for (WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
517      if (await observer.didPushRoute(route))
518        return;
519    }
520  }
521
522  Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
523    switch (methodCall.method) {
524      case 'popRoute':
525        return handlePopRoute();
526      case 'pushRoute':
527        return handlePushRoute(methodCall.arguments);
528    }
529    return Future<dynamic>.value();
530  }
531
532  @override
533  void handleAppLifecycleStateChanged(AppLifecycleState state) {
534    super.handleAppLifecycleStateChanged(state);
535    for (WidgetsBindingObserver observer in _observers)
536      observer.didChangeAppLifecycleState(state);
537  }
538
539  /// Called when the operating system notifies the application of a memory
540  /// pressure situation.
541  ///
542  /// Notifies all the observers using
543  /// [WidgetsBindingObserver.didHaveMemoryPressure].
544  ///
545  /// This method exposes the `memoryPressure` notification from
546  /// [SystemChannels.system].
547  void handleMemoryPressure() {
548    for (WidgetsBindingObserver observer in _observers)
549      observer.didHaveMemoryPressure();
550  }
551
552  Future<void> _handleSystemMessage(Object systemMessage) async {
553    final Map<String, dynamic> message = systemMessage;
554    final String type = message['type'];
555    switch (type) {
556      case 'memoryPressure':
557        handleMemoryPressure();
558        break;
559    }
560    return;
561  }
562
563  bool _needToReportFirstFrame = true;
564  int _deferFirstFrameReportCount = 0;
565  bool get _reportFirstFrame => _deferFirstFrameReportCount == 0;
566
567
568  final Completer<void> _firstFrameCompleter = Completer<void>();
569
570  /// Whether the Flutter engine has rasterized the first frame.
571  ///
572  /// {@macro flutter.frame_rasterized_vs_presented}
573  ///
574  /// See also:
575  ///
576  ///  * [waitUntilFirstFrameRasterized], the future when [firstFrameRasterized]
577  ///    becomes true.
578  bool get firstFrameRasterized => _firstFrameCompleter.isCompleted;
579
580  /// A future that completes when the Flutter engine has rasterized the first
581  /// frame.
582  ///
583  /// {@macro flutter.frame_rasterize_vs_presented}
584  ///
585  /// See also:
586  ///
587  ///  * [firstFrameRasterized], whether this future has completed or not.
588  Future<void> get waitUntilFirstFrameRasterized => _firstFrameCompleter.future;
589
590  /// Whether the first frame has finished building.
591  ///
592  /// Only useful in profile and debug builds; in release builds, this always
593  /// return false. This can be deferred using [deferFirstFrameReport] and
594  /// [allowFirstFrameReport]. The value is set at the end of the call to
595  /// [drawFrame].
596  ///
597  /// This value can also be obtained over the VM service protocol as
598  /// `ext.flutter.didSendFirstFrameEvent`.
599  ///
600  /// See also:
601  ///
602  ///  * [firstFrameRasterized], whether the first frame has finished rendering.
603  bool get debugDidSendFirstFrameEvent => !_needToReportFirstFrame;
604
605  /// Tell the framework not to report the frame it is building as a "useful"
606  /// first frame until there is a corresponding call to [allowFirstFrameReport].
607  ///
608  /// This is used by [WidgetsApp] to avoid reporting frames that aren't useful
609  /// during startup as the "first frame".
610  void deferFirstFrameReport() {
611    if (!kReleaseMode) {
612      assert(_deferFirstFrameReportCount >= 0);
613      _deferFirstFrameReportCount += 1;
614    }
615  }
616
617  /// When called after [deferFirstFrameReport]: tell the framework to report
618  /// the frame it is building as a "useful" first frame.
619  ///
620  /// This method may only be called once for each corresponding call
621  /// to [deferFirstFrameReport].
622  ///
623  /// This is used by [WidgetsApp] to report when the first useful frame is
624  /// painted.
625  void allowFirstFrameReport() {
626    if (!kReleaseMode) {
627      assert(_deferFirstFrameReportCount >= 1);
628      _deferFirstFrameReportCount -= 1;
629    }
630  }
631
632  void _handleBuildScheduled() {
633    // If we're in the process of building dirty elements, then changes
634    // should not trigger a new frame.
635    assert(() {
636      if (debugBuildingDirtyElements) {
637        throw FlutterError(
638          'Build scheduled during frame.\n'
639          'While the widget tree was being built, laid out, and painted, '
640          'a new frame was scheduled to rebuild the widget tree. '
641          'This might be because setState() was called from a layout or '
642          'paint callback. '
643          'If a change is needed to the widget tree, it should be applied '
644          'as the tree is being built. Scheduling a change for the subsequent '
645          'frame instead results in an interface that lags behind by one frame. '
646          'If this was done to make your build dependent on a size measured at '
647          'layout time, consider using a LayoutBuilder, CustomSingleChildLayout, '
648          'or CustomMultiChildLayout. If, on the other hand, the one frame delay '
649          'is the desired effect, for example because this is an '
650          'animation, consider scheduling the frame in a post-frame callback '
651          'using SchedulerBinding.addPostFrameCallback or '
652          'using an AnimationController to trigger the animation.'
653        );
654      }
655      return true;
656    }());
657    ensureVisualUpdate();
658  }
659
660  /// Whether we are currently in a frame. This is used to verify
661  /// that frames are not scheduled redundantly.
662  ///
663  /// This is public so that test frameworks can change it.
664  ///
665  /// This flag is not used in release builds.
666  @protected
667  bool debugBuildingDirtyElements = false;
668
669  /// Pump the build and rendering pipeline to generate a frame.
670  ///
671  /// This method is called by [handleDrawFrame], which itself is called
672  /// automatically by the engine when when it is time to lay out and paint a
673  /// frame.
674  ///
675  /// Each frame consists of the following phases:
676  ///
677  /// 1. The animation phase: The [handleBeginFrame] method, which is registered
678  /// with [Window.onBeginFrame], invokes all the transient frame callbacks
679  /// registered with [scheduleFrameCallback], in
680  /// registration order. This includes all the [Ticker] instances that are
681  /// driving [AnimationController] objects, which means all of the active
682  /// [Animation] objects tick at this point.
683  ///
684  /// 2. Microtasks: After [handleBeginFrame] returns, any microtasks that got
685  /// scheduled by transient frame callbacks get to run. This typically includes
686  /// callbacks for futures from [Ticker]s and [AnimationController]s that
687  /// completed this frame.
688  ///
689  /// After [handleBeginFrame], [handleDrawFrame], which is registered with
690  /// [Window.onDrawFrame], is called, which invokes all the persistent frame
691  /// callbacks, of which the most notable is this method, [drawFrame], which
692  /// proceeds as follows:
693  ///
694  /// 3. The build phase: All the dirty [Element]s in the widget tree are
695  /// rebuilt (see [State.build]). See [State.setState] for further details on
696  /// marking a widget dirty for building. See [BuildOwner] for more information
697  /// on this step.
698  ///
699  /// 4. The layout phase: All the dirty [RenderObject]s in the system are laid
700  /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
701  /// for further details on marking an object dirty for layout.
702  ///
703  /// 5. The compositing bits phase: The compositing bits on any dirty
704  /// [RenderObject] objects are updated. See
705  /// [RenderObject.markNeedsCompositingBitsUpdate].
706  ///
707  /// 6. The paint phase: All the dirty [RenderObject]s in the system are
708  /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
709  /// [RenderObject.markNeedsPaint] for further details on marking an object
710  /// dirty for paint.
711  ///
712  /// 7. The compositing phase: The layer tree is turned into a [Scene] and
713  /// sent to the GPU.
714  ///
715  /// 8. The semantics phase: All the dirty [RenderObject]s in the system have
716  /// their semantics updated (see [RenderObject.assembleSemanticsNode]). This
717  /// generates the [SemanticsNode] tree. See
718  /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
719  /// object dirty for semantics.
720  ///
721  /// For more details on steps 4-8, see [PipelineOwner].
722  ///
723  /// 9. The finalization phase in the widgets layer: The widgets tree is
724  /// finalized. This causes [State.dispose] to be invoked on any objects that
725  /// were removed from the widgets tree this frame. See
726  /// [BuildOwner.finalizeTree] for more details.
727  ///
728  /// 10. The finalization phase in the scheduler layer: After [drawFrame]
729  /// returns, [handleDrawFrame] then invokes post-frame callbacks (registered
730  /// with [addPostFrameCallback]).
731  //
732  // When editing the above, also update rendering/binding.dart's copy.
733  @override
734  void drawFrame() {
735    assert(!debugBuildingDirtyElements);
736    assert(() {
737      debugBuildingDirtyElements = true;
738      return true;
739    }());
740
741    if (_needToReportFirstFrame && _reportFirstFrame) {
742      assert(!_firstFrameCompleter.isCompleted);
743      // TODO(liyuqian): use a broadcast stream approach
744      final TimingsCallback oldCallback = WidgetsBinding.instance.window.onReportTimings;
745      WidgetsBinding.instance.window.onReportTimings = (List<FrameTiming> timings) {
746        if (!kReleaseMode) {
747          developer.Timeline.instantSync('Rasterized first useful frame');
748          developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
749        }
750        if (oldCallback != null) {
751          oldCallback(timings);
752        }
753        WidgetsBinding.instance.window.onReportTimings = oldCallback;
754        _firstFrameCompleter.complete();
755      };
756    }
757
758    try {
759      if (renderViewElement != null)
760        buildOwner.buildScope(renderViewElement);
761      super.drawFrame();
762      buildOwner.finalizeTree();
763    } finally {
764      assert(() {
765        debugBuildingDirtyElements = false;
766        return true;
767      }());
768    }
769    if (!kReleaseMode) {
770      if (_needToReportFirstFrame && _reportFirstFrame) {
771        developer.Timeline.instantSync('Widgets built first useful frame');
772      }
773    }
774    _needToReportFirstFrame = false;
775  }
776
777  /// The [Element] that is at the root of the hierarchy (and which wraps the
778  /// [RenderView] object at the root of the rendering hierarchy).
779  ///
780  /// This is initialized the first time [runApp] is called.
781  Element get renderViewElement => _renderViewElement;
782  Element _renderViewElement;
783
784  /// Takes a widget and attaches it to the [renderViewElement], creating it if
785  /// necessary.
786  ///
787  /// This is called by [runApp] to configure the widget tree.
788  ///
789  /// See also [RenderObjectToWidgetAdapter.attachToRenderTree].
790  void attachRootWidget(Widget rootWidget) {
791    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
792      container: renderView,
793      debugShortDescription: '[root]',
794      child: rootWidget,
795    ).attachToRenderTree(buildOwner, renderViewElement);
796  }
797
798  /// Whether the [renderViewElement] has been initialized.
799  ///
800  /// This will be false until [runApp] is called (or [WidgetTester.pumpWidget]
801  /// is called in the context of a [TestWidgetsFlutterBinding]).
802  bool get isRootWidgetAttached => _renderViewElement != null;
803
804  @override
805  Future<void> performReassemble() {
806    assert(() {
807      WidgetInspectorService.instance.performReassemble();
808      return true;
809    }());
810
811    deferFirstFrameReport();
812    if (renderViewElement != null)
813      buildOwner.reassemble(renderViewElement);
814    return super.performReassemble().then((void value) {
815      allowFirstFrameReport();
816    });
817  }
818}
819
820/// Inflate the given widget and attach it to the screen.
821///
822/// The widget is given constraints during layout that force it to fill the
823/// entire screen. If you wish to align your widget to one side of the screen
824/// (e.g., the top), consider using the [Align] widget. If you wish to center
825/// your widget, you can also use the [Center] widget
826///
827/// Calling [runApp] again will detach the previous root widget from the screen
828/// and attach the given widget in its place. The new widget tree is compared
829/// against the previous widget tree and any differences are applied to the
830/// underlying render tree, similar to what happens when a [StatefulWidget]
831/// rebuilds after calling [State.setState].
832///
833/// Initializes the binding using [WidgetsFlutterBinding] if necessary.
834///
835/// See also:
836///
837///  * [WidgetsBinding.attachRootWidget], which creates the root widget for the
838///    widget hierarchy.
839///  * [RenderObjectToWidgetAdapter.attachToRenderTree], which creates the root
840///    element for the element hierarchy.
841///  * [WidgetsBinding.handleBeginFrame], which pumps the widget pipeline to
842///    ensure the widget, element, and render trees are all built.
843void runApp(Widget app) {
844  WidgetsFlutterBinding.ensureInitialized()
845    ..attachRootWidget(app)
846    ..scheduleWarmUpFrame();
847}
848
849/// Print a string representation of the currently running app.
850void debugDumpApp() {
851  assert(WidgetsBinding.instance != null);
852  String mode = 'RELEASE MODE';
853  assert(() { mode = 'CHECKED MODE'; return true; }());
854  debugPrint('${WidgetsBinding.instance.runtimeType} - $mode');
855  if (WidgetsBinding.instance.renderViewElement != null) {
856    debugPrint(WidgetsBinding.instance.renderViewElement.toStringDeep());
857  } else {
858    debugPrint('<no tree currently mounted>');
859  }
860}
861
862/// A bridge from a [RenderObject] to an [Element] tree.
863///
864/// The given container is the [RenderObject] that the [Element] tree should be
865/// inserted into. It must be a [RenderObject] that implements the
866/// [RenderObjectWithChildMixin] protocol. The type argument `T` is the kind of
867/// [RenderObject] that the container expects as its child.
868///
869/// Used by [runApp] to bootstrap applications.
870class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
871  /// Creates a bridge from a [RenderObject] to an [Element] tree.
872  ///
873  /// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
874  RenderObjectToWidgetAdapter({
875    this.child,
876    this.container,
877    this.debugShortDescription,
878  }) : super(key: GlobalObjectKey(container));
879
880  /// The widget below this widget in the tree.
881  ///
882  /// {@macro flutter.widgets.child}
883  final Widget child;
884
885  /// The [RenderObject] that is the parent of the [Element] created by this widget.
886  final RenderObjectWithChildMixin<T> container;
887
888  /// A short description of this widget used by debugging aids.
889  final String debugShortDescription;
890
891  @override
892  RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
893
894  @override
895  RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;
896
897  @override
898  void updateRenderObject(BuildContext context, RenderObject renderObject) { }
899
900  /// Inflate this widget and actually set the resulting [RenderObject] as the
901  /// child of [container].
902  ///
903  /// If `element` is null, this function will create a new element. Otherwise,
904  /// the given element will have an update scheduled to switch to this widget.
905  ///
906  /// Used by [runApp] to bootstrap applications.
907  RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) {
908    if (element == null) {
909      owner.lockState(() {
910        element = createElement();
911        assert(element != null);
912        element.assignOwner(owner);
913      });
914      owner.buildScope(element, () {
915        element.mount(null, null);
916      });
917    } else {
918      element._newWidget = this;
919      element.markNeedsBuild();
920    }
921    return element;
922  }
923
924  @override
925  String toStringShort() => debugShortDescription ?? super.toStringShort();
926}
927
928/// A [RootRenderObjectElement] that is hosted by a [RenderObject].
929///
930/// This element class is the instantiation of a [RenderObjectToWidgetAdapter]
931/// widget. It can be used only as the root of an [Element] tree (it cannot be
932/// mounted into another [Element]; it's parent must be null).
933///
934/// In typical usage, it will be instantiated for a [RenderObjectToWidgetAdapter]
935/// whose container is the [RenderView] that connects to the Flutter engine. In
936/// this usage, it is normally instantiated by the bootstrapping logic in the
937/// [WidgetsFlutterBinding] singleton created by [runApp].
938class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObjectElement {
939  /// Creates an element that is hosted by a [RenderObject].
940  ///
941  /// The [RenderObject] created by this element is not automatically set as a
942  /// child of the hosting [RenderObject]. To actually attach this element to
943  /// the render tree, call [RenderObjectToWidgetAdapter.attachToRenderTree].
944  RenderObjectToWidgetElement(RenderObjectToWidgetAdapter<T> widget) : super(widget);
945
946  @override
947  RenderObjectToWidgetAdapter<T> get widget => super.widget;
948
949  Element _child;
950
951  static const Object _rootChildSlot = Object();
952
953  @override
954  void visitChildren(ElementVisitor visitor) {
955    if (_child != null)
956      visitor(_child);
957  }
958
959  @override
960  void forgetChild(Element child) {
961    assert(child == _child);
962    _child = null;
963  }
964
965  @override
966  void mount(Element parent, dynamic newSlot) {
967    assert(parent == null);
968    super.mount(parent, newSlot);
969    _rebuild();
970  }
971
972  @override
973  void update(RenderObjectToWidgetAdapter<T> newWidget) {
974    super.update(newWidget);
975    assert(widget == newWidget);
976    _rebuild();
977  }
978
979  // When we are assigned a new widget, we store it here
980  // until we are ready to update to it.
981  Widget _newWidget;
982
983  @override
984  void performRebuild() {
985    if (_newWidget != null) {
986      // _newWidget can be null if, for instance, we were rebuilt
987      // due to a reassemble.
988      final Widget newWidget = _newWidget;
989      _newWidget = null;
990      update(newWidget);
991    }
992    super.performRebuild();
993    assert(_newWidget == null);
994  }
995
996  void _rebuild() {
997    try {
998      _child = updateChild(_child, widget.child, _rootChildSlot);
999      assert(_child != null);
1000    } catch (exception, stack) {
1001      final FlutterErrorDetails details = FlutterErrorDetails(
1002        exception: exception,
1003        stack: stack,
1004        library: 'widgets library',
1005        context: ErrorDescription('attaching to the render tree'),
1006      );
1007      FlutterError.reportError(details);
1008      final Widget error = ErrorWidget.builder(details);
1009      _child = updateChild(null, error, _rootChildSlot);
1010    }
1011  }
1012
1013  @override
1014  RenderObjectWithChildMixin<T> get renderObject => super.renderObject;
1015
1016  @override
1017  void insertChildRenderObject(RenderObject child, dynamic slot) {
1018    assert(slot == _rootChildSlot);
1019    assert(renderObject.debugValidateChild(child));
1020    renderObject.child = child;
1021  }
1022
1023  @override
1024  void moveChildRenderObject(RenderObject child, dynamic slot) {
1025    assert(false);
1026  }
1027
1028  @override
1029  void removeChildRenderObject(RenderObject child) {
1030    assert(renderObject.child == child);
1031    renderObject.child = null;
1032  }
1033}
1034
1035/// A concrete binding for applications based on the Widgets framework.
1036///
1037/// This is the glue that binds the framework to the Flutter engine.
1038class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
1039
1040  /// Returns an instance of the [WidgetsBinding], creating and
1041  /// initializing it if necessary. If one is created, it will be a
1042  /// [WidgetsFlutterBinding]. If one was previously initialized, then
1043  /// it will at least implement [WidgetsBinding].
1044  ///
1045  /// You only need to call this method if you need the binding to be
1046  /// initialized before calling [runApp].
1047  ///
1048  /// In the `flutter_test` framework, [testWidgets] initializes the
1049  /// binding instance to a [TestWidgetsFlutterBinding], not a
1050  /// [WidgetsFlutterBinding].
1051  static WidgetsBinding ensureInitialized() {
1052    if (WidgetsBinding.instance == null)
1053      WidgetsFlutterBinding();
1054    return WidgetsBinding.instance;
1055  }
1056}
1057