// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. part of dart.ui; /// Signature of callbacks that have no arguments and return no data. typedef VoidCallback = void Function(); /// Signature for [PlatformDispatcher.onBeginFrame]. /// /// The `duration` argument is the point at which the current frame interval /// began, expressed as a duration since some epoch. The epoch in all /// frames will be the same, but it may not match [DateTime]'s epoch. /// /// For any two frames `a` and `b` such that the frame number of `a` is less /// than the frame number of `b`, the duration argument for `a` will be less /// than or equal to the duration argument for `b`. typedef FrameCallback = void Function(Duration duration); /// Signature for [PlatformDispatcher.onReportTimings]. /// /// {@template dart.ui.TimingsCallback.list} /// The callback takes a list of [FrameTiming] because it may not be /// immediately triggered after each frame. Instead, Flutter tries to batch /// frames together and send all their timings at once to decrease the /// overhead (as this is available in the release mode). The list is sorted in /// ascending order of time (earliest frame first). The timing of any frame /// will be sent within about 1 second (100ms if in the profile/debug mode) /// even if there are no later frames to batch. The timing of the first frame /// will be sent immediately without batching. /// {@endtemplate} typedef TimingsCallback = void Function(List timings); /// Signature for [PlatformDispatcher.onPointerDataPacket]. typedef PointerDataPacketCallback = void Function(PointerDataPacket packet); /// Signature for [PlatformDispatcher.onKeyData]. /// /// The callback should return true if the key event has been handled by the /// framework and should not be propagated further. typedef KeyDataCallback = bool Function(KeyData data); /// Signature for [PlatformDispatcher.onSemanticsActionEvent]. typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action); /// Signature for responses to platform messages. /// /// Used as a parameter to [PlatformDispatcher.sendPlatformMessage] and /// [PlatformDispatcher.onPlatformMessage]. typedef PlatformMessageResponseCallback = void Function(ByteData? data); /// Deprecated. Migrate to [ChannelBuffers.setListener] instead. /// /// Signature for [PlatformDispatcher.onPlatformMessage]. @Deprecated( 'Migrate to ChannelBuffers.setListener instead. ' 'This feature was deprecated after v3.11.0-20.0.pre.', ) typedef PlatformMessageCallback = void Function(String name, ByteData? data, PlatformMessageResponseCallback? callback); // Signature for _setNeedsReportTimings. typedef _SetNeedsReportTimingsFunc = void Function(bool value); /// Signature for [PlatformDispatcher.onError]. /// /// If this method returns false, the engine may use some fallback method to /// provide information about the error. /// /// After calling this method, the process or the VM may terminate. Some severe /// unhandled errors may not be able to call this method either, such as Dart /// compilation errors or process terminating errors. typedef ErrorCallback = bool Function(Object exception, StackTrace stackTrace); // A gesture setting value that indicates it has not been set by the engine. const double _kUnsetGestureSetting = -1.0; // A message channel to receive KeyData from the platform. // // See embedder.cc::kFlutterKeyDataChannel for more information. const String _kFlutterKeyDataChannel = 'flutter/keydata'; @pragma('vm:entry-point') ByteData? _wrapUnmodifiableByteData(ByteData? byteData) => byteData?.asUnmodifiableView(); /// A token that represents a root isolate. class RootIsolateToken { RootIsolateToken._(this._token); /// An enumeration representing the root isolate (0 if not a root isolate). final int _token; /// The token for the root isolate that is executing this Dart code. If this /// Dart code is not executing on a root isolate [instance] will be null. static final RootIsolateToken? instance = () { final int token = __getRootIsolateToken(); return token == 0 ? null : RootIsolateToken._(token); }(); @Native(symbol: 'PlatformConfigurationNativeApi::GetRootIsolateToken') external static int __getRootIsolateToken(); } /// Platform event dispatcher singleton. /// /// The most basic interface to the host operating system's interface. /// /// This is the central entry point for platform messages and configuration /// events from the platform. /// /// It exposes the core scheduler API, the input event callback, the graphics /// drawing API, and other such core services. /// /// It manages the list of the application's [views] as well as the /// [configuration] of various platform attributes. /// /// Consider avoiding static references to this singleton through /// [PlatformDispatcher.instance] and instead prefer using a binding for /// dependency resolution such as `WidgetsBinding.instance.platformDispatcher`. /// See [PlatformDispatcher.instance] for more information about why this is /// preferred. class PlatformDispatcher { /// Private constructor, since only dart:ui is supposed to create one of /// these. Use [instance] to access the singleton. PlatformDispatcher._() { _setNeedsReportTimings = _nativeSetNeedsReportTimings; } /// The [PlatformDispatcher] singleton. /// /// Consider avoiding static references to this singleton through /// [PlatformDispatcher.instance] and instead prefer using a binding for /// dependency resolution such as `WidgetsBinding.instance.platformDispatcher`. /// /// Static access of this object means that Flutter has few, if any options to /// fake or mock the given object in tests. Even in cases where Dart offers /// special language constructs to forcefully shadow such properties, those /// mechanisms would only be reasonable for tests and they would not be /// reasonable for a future of Flutter where we legitimately want to select an /// appropriate implementation at runtime. /// /// The only place that `WidgetsBinding.instance.platformDispatcher` is /// inappropriate is if access to these APIs is required before the binding is /// initialized by invoking `runApp()` or /// `WidgetsFlutterBinding.instance.ensureInitialized()`. In that case, it is /// necessary (though unfortunate) to use the [PlatformDispatcher.instance] /// object statically. static PlatformDispatcher get instance => _instance; static final PlatformDispatcher _instance = PlatformDispatcher._(); _PlatformConfiguration _configuration = const _PlatformConfiguration(); /// Called when the platform configuration changes. /// /// The engine invokes this callback in the same zone in which the callback /// was set. VoidCallback? get onPlatformConfigurationChanged => _onPlatformConfigurationChanged; VoidCallback? _onPlatformConfigurationChanged; Zone _onPlatformConfigurationChangedZone = Zone.root; set onPlatformConfigurationChanged(VoidCallback? callback) { _onPlatformConfigurationChanged = callback; _onPlatformConfigurationChangedZone = Zone.current; } /// The current list of displays. /// /// If any of their configurations change, [onMetricsChanged] will be called. /// /// To get the display for a [FlutterView], use [FlutterView.display]. /// /// Platforms may limit what information is available to the application with /// regard to secondary displays and/or displays that do not have an active /// application window. /// /// Presently, on Android and Web this collection will only contain the /// display that the current window is on. On iOS, it will only contains the /// main display on the phone or tablet. On Desktops other than Linux, it will /// contain only a main display with a valid refresh rate but invalid size and /// device pixel ratio values. // TODO(dnfield): Update these docs when https://github.com/flutter/flutter/issues/125939 // and https://github.com/flutter/flutter/issues/125938 are resolved. Iterable get displays => _displays.values; final Map _displays = {}; /// The current list of views, including top level platform windows used by /// the application. /// /// If any of their configurations change, [onMetricsChanged] will be called. Iterable get views => _views.values; final Map _views = {}; /// Returns the [FlutterView] with the provided ID if one exists, or null /// otherwise. FlutterView? view({required int id}) => _views[id]; /// The [FlutterView] provided by the engine if the platform is unable to /// create windows, or, for backwards compatibility. /// /// If the platform provides an implicit view, it can be used to bootstrap /// the framework. This is common for platforms designed for single-view /// applications like mobile devices with a single display. /// /// Applications and libraries must not rely on this property being set /// as it may be null depending on the engine's configuration. Instead, /// consider using [View.of] to lookup the [FlutterView] the current /// [BuildContext] is drawing into. /// /// While the properties on the referenced [FlutterView] may change, /// the reference itself is guaranteed to never change over the lifetime /// of the application: if this property is null at startup, it will remain /// so throughout the entire lifetime of the application. If it points to a /// specific [FlutterView], it will continue to point to the same view until /// the application is shut down (although the engine may replace or remove /// the underlying backing surface of the view at its discretion). /// /// See also: /// /// * [View.of], for accessing the current view. /// * [PlatformDispatcher.views] for a list of all [FlutterView]s provided /// by the platform. FlutterView? get implicitView { final FlutterView? result = _views[_implicitViewId]; // Make sure [implicitView] agrees with `_implicitViewId`. assert( (result != null) == (_implicitViewId != null), (_implicitViewId != null) ? 'The implicit view ID is $_implicitViewId, but the implicit view does not exist.' : 'The implicit view ID is null, but the implicit view exists.', ); // Make sure [implicitView] never chages. assert(() { if (_debugRecordedLastImplicitView) { assert( identical(_debugLastImplicitView, result), 'The implicitView has changed:\n' 'Last: $_debugLastImplicitView\nCurrent: $result', ); } else { _debugLastImplicitView = result; _debugRecordedLastImplicitView = true; } return true; }()); return result; } FlutterView? _debugLastImplicitView; bool _debugRecordedLastImplicitView = false; /// A callback that is invoked whenever the [ViewConfiguration] of any of the /// [views] changes. /// /// For example when the device is rotated or when the application is resized /// (e.g. when showing applications side-by-side on Android), /// `onMetricsChanged` is called. /// /// The engine invokes this callback in the same zone in which the callback /// was set. /// /// The framework registers with this callback and updates the layout /// appropriately. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// register for notifications when this is called. /// * [MediaQuery.of], a simpler mechanism for the same. VoidCallback? get onMetricsChanged => _onMetricsChanged; VoidCallback? _onMetricsChanged; Zone _onMetricsChangedZone = Zone.root; set onMetricsChanged(VoidCallback? callback) { _onMetricsChanged = callback; _onMetricsChangedZone = Zone.current; } // Called from the engine, via hooks.dart // // Adds a new view with the specific view configuration. // // The implicit view must be added before [implicitView] is first called, // which is typically the main function. void _addView(int id, _ViewConfiguration viewConfiguration) { assert(!_views.containsKey(id), 'View ID $id already exists.'); _views[id] = FlutterView._(id, this, viewConfiguration); _invoke(onMetricsChanged, _onMetricsChangedZone); } // Called from the engine, via hooks.dart // // Removes the specific view. // // The target view must must exist. The implicit view must not be removed, // or an assertion will be triggered. void _removeView(int id) { assert(id != _implicitViewId, 'The implicit view #$id can not be removed.'); if (id == _implicitViewId) { return; } assert(_views.containsKey(id), 'View ID $id does not exist.'); _views.remove(id); _invoke(onMetricsChanged, _onMetricsChangedZone); } void _sendViewFocusEvent(ViewFocusEvent event) { _invoke1(onViewFocusChange, _onViewFocusChangeZone, event); } /// Opaque engine identifier for the engine running current isolate. Can be used /// in native code to retrieve the engine instance. /// The identifier is valid while the isolate is running. int? get engineId => _engineId; int? _engineId; // Called from the engine, via hooks.dart. // // Updates the available displays. void _updateDisplays(List displays) { _displays.clear(); for (final display in displays) { _displays[display.id] = display; } _invoke(onMetricsChanged, _onMetricsChangedZone); } // Called from the engine, via hooks.dart // // Updates the metrics of the window with the given id. void _updateWindowMetrics(int viewId, _ViewConfiguration viewConfiguration) { assert(_views.containsKey(viewId), 'View $viewId does not exist.'); _views[viewId]!._viewConfiguration = viewConfiguration; _invoke(onMetricsChanged, _onMetricsChangedZone); } /// A callback invoked immediately after the focus is transitioned across [FlutterView]s. /// /// When the platform moves the focus from one [FlutterView] to another, this /// callback is invoked indicating the new view that has focus and the direction /// in which focus was received. For example, if focus is moved to the [FlutterView] /// with ID 2 in the forward direction (could be the result of pressing tab) /// the callback receives a [ViewFocusEvent] with [ViewFocusState.focused] and /// [ViewFocusDirection.forward]. /// /// Typically, receivers of this event respond by moving the focus to the first /// focusable widget inside the [FlutterView] with ID 2. If a view receives /// focus in the backward direction (could be the result of pressing shift + tab), /// typically the last focusable widget inside that view is focused. /// /// The platform may remove focus from a [FlutterView]. For example, on the web, /// the browser can move focus to another element, or to the browser's built-in UI. /// On desktop, the operating system can switch to another window (e.g. using Alt + Tab on Windows). /// In scenarios like these, [onViewFocusChange] will be invoked with [ViewFocusState.unfocused] and /// [ViewFocusDirection.undefined]. /// /// Receivers typically respond to this event by removing all focus indications /// from the app. /// /// Apps can also programmatically request to move the focus to a desired /// [FlutterView] by calling [requestViewFocusChange]. /// /// The callback is invoked in the same zone in which the callback was set. /// /// See also: /// /// * [requestViewFocusChange] to programmatically instruct the platform to move focus to a different [FlutterView]. /// * [ViewFocusState] for a list of allowed focus transitions. /// * [ViewFocusDirection] for a list of allowed focus directions. /// * [ViewFocusEvent], which is the event object provided to the callback. ViewFocusChangeCallback? get onViewFocusChange => _onViewFocusChange; ViewFocusChangeCallback? _onViewFocusChange; // ignore: unused_field, field will be used when platforms other than web use these focus APIs. Zone _onViewFocusChangeZone = Zone.root; set onViewFocusChange(ViewFocusChangeCallback? callback) { _onViewFocusChange = callback; _onViewFocusChangeZone = Zone.current; } /// Requests a focus change of the [FlutterView] with ID [viewId]. /// /// If an app would like to request the engine to move focus, in forward direction, /// to the [FlutterView] with ID 1 it should call this method with [ViewFocusState.focused] /// and [ViewFocusDirection.forward]. /// /// There is no need to call this method if the view in question already has /// focus as it won't have any effect. /// /// A call to this method will lead to the engine calling [onViewFocusChange] /// if the request is successfully fulfilled. /// /// See also: /// /// * [onViewFocusChange], a callback to subscribe to view focus change events. void requestViewFocusChange({ required int viewId, required ViewFocusState state, required ViewFocusDirection direction, }) { _requestViewFocusChange(viewId, state.index, direction.index); } @Native( symbol: 'PlatformConfigurationNativeApi::RequestViewFocusChange', ) external static void _requestViewFocusChange(int viewId, int state, int direction); /// A callback invoked when any view begins a frame. /// /// A callback that is invoked to notify the application that it is an /// appropriate time to provide a scene using the [SceneBuilder] API and the /// [FlutterView.render] method. /// /// When possible, this is driven by the hardware VSync signal of the attached /// screen with the highest VSync rate. This is only called if /// [PlatformDispatcher.scheduleFrame] has been called since the last time /// this callback was invoked. FrameCallback? get onBeginFrame => _onBeginFrame; FrameCallback? _onBeginFrame; Zone _onBeginFrameZone = Zone.root; set onBeginFrame(FrameCallback? callback) { _onBeginFrame = callback; _onBeginFrameZone = Zone.current; } // Called from the engine, via hooks.dart void _beginFrame(int microseconds) { _invoke1(onBeginFrame, _onBeginFrameZone, Duration(microseconds: microseconds)); } /// A callback that is invoked for each frame after [onBeginFrame] has /// completed and after the microtask queue has been drained. /// /// This can be used to implement a second phase of frame rendering that /// happens after any deferred work queued by the [onBeginFrame] phase. VoidCallback? get onDrawFrame => _onDrawFrame; VoidCallback? _onDrawFrame; Zone _onDrawFrameZone = Zone.root; set onDrawFrame(VoidCallback? callback) { _onDrawFrame = callback; _onDrawFrameZone = Zone.current; } // Called from the engine, via hooks.dart void _drawFrame() { _invoke(onDrawFrame, _onDrawFrameZone); } /// A callback that is invoked when pointer data is available. /// /// The framework invokes this callback in the same zone in which the callback /// was set. /// /// See also: /// /// * [GestureBinding], the Flutter framework class which manages pointer /// events. PointerDataPacketCallback? get onPointerDataPacket => _onPointerDataPacket; PointerDataPacketCallback? _onPointerDataPacket; Zone _onPointerDataPacketZone = Zone.root; set onPointerDataPacket(PointerDataPacketCallback? callback) { _onPointerDataPacket = callback; _onPointerDataPacketZone = Zone.current; } // Called from the engine, via hooks.dart void _dispatchPointerDataPacket(ByteData packet) { if (onPointerDataPacket != null) { _invoke1( onPointerDataPacket, _onPointerDataPacketZone, _unpackPointerDataPacket(packet), ); } } // This value must match kPointerDataFieldCount in pointer_data.cc. (The // pointer_data.cc also lists other locations that must be kept consistent.) static const int _kPointerDataFieldCount = 36; static PointerDataPacket _unpackPointerDataPacket(ByteData packet) { const int kStride = Int64List.bytesPerElement; const int kBytesPerPointerData = _kPointerDataFieldCount * kStride; final int length = packet.lengthInBytes ~/ kBytesPerPointerData; assert(length * kBytesPerPointerData == packet.lengthInBytes); final data = []; for (var i = 0; i < length; ++i) { int offset = i * _kPointerDataFieldCount; data.add( PointerData( // The unpacking code must match the struct in pointer_data.h. embedderId: packet.getInt64(kStride * offset++, _kFakeHostEndian), timeStamp: Duration(microseconds: packet.getInt64(kStride * offset++, _kFakeHostEndian)), change: PointerChange.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], kind: PointerDeviceKind.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], signalKind: PointerSignalKind.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], device: packet.getInt64(kStride * offset++, _kFakeHostEndian), pointerIdentifier: packet.getInt64(kStride * offset++, _kFakeHostEndian), physicalX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), physicalY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), physicalDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), physicalDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), buttons: packet.getInt64(kStride * offset++, _kFakeHostEndian), obscured: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0, synthesized: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0, pressure: packet.getFloat64(kStride * offset++, _kFakeHostEndian), pressureMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), pressureMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), distance: packet.getFloat64(kStride * offset++, _kFakeHostEndian), distanceMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), size: packet.getFloat64(kStride * offset++, _kFakeHostEndian), radiusMajor: packet.getFloat64(kStride * offset++, _kFakeHostEndian), radiusMinor: packet.getFloat64(kStride * offset++, _kFakeHostEndian), radiusMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), radiusMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), orientation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), tilt: packet.getFloat64(kStride * offset++, _kFakeHostEndian), platformData: packet.getInt64(kStride * offset++, _kFakeHostEndian), scrollDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), scrollDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), panX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), panY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), panDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), panDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), scale: packet.getFloat64(kStride * offset++, _kFakeHostEndian), rotation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), viewId: packet.getInt64(kStride * offset++, _kFakeHostEndian), ), ); assert(offset == (i + 1) * _kPointerDataFieldCount); } return PointerDataPacket(data: data); } static ChannelCallback _keyDataListener(KeyDataCallback onKeyData, Zone zone) => (ByteData? packet, PlatformMessageResponseCallback callback) { _invoke1( (KeyData keyData) { final bool handled = onKeyData(keyData); final response = Uint8List(1); response[0] = handled ? 1 : 0; callback(response.buffer.asByteData()); }, zone, _unpackKeyData(packet!), ); }; /// A callback that is invoked when key data is available. /// /// The framework invokes this callback in the same zone in which the callback /// was set. /// /// The callback should return true if the key event has been handled by the /// framework and should not be propagated further. KeyDataCallback? get onKeyData => _onKeyData; KeyDataCallback? _onKeyData; set onKeyData(KeyDataCallback? callback) { _onKeyData = callback; if (callback != null) { channelBuffers.setListener(_kFlutterKeyDataChannel, _keyDataListener(callback, Zone.current)); } else { channelBuffers.clearListener(_kFlutterKeyDataChannel); } } // If this value changes, update the encoding code in the following files: // // * key_data.h (kKeyDataFieldCount) // * KeyData.java (KeyData.FIELD_COUNT) static const int _kKeyDataFieldCount = 6; // The packet structure is described in `key_data_packet.h`. static KeyData _unpackKeyData(ByteData packet) { const int kStride = Int64List.bytesPerElement; var offset = 0; final int charDataSize = packet.getUint64(kStride * offset++, _kFakeHostEndian); final String? character = charDataSize == 0 ? null : utf8.decoder.convert( packet.buffer.asUint8List(kStride * (offset + _kKeyDataFieldCount), charDataSize), ); final keyData = KeyData( timeStamp: Duration(microseconds: packet.getUint64(kStride * offset++, _kFakeHostEndian)), type: KeyEventType.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], physical: packet.getUint64(kStride * offset++, _kFakeHostEndian), logical: packet.getUint64(kStride * offset++, _kFakeHostEndian), character: character, synthesized: packet.getUint64(kStride * offset++, _kFakeHostEndian) != 0, ); return keyData; } /// A callback that is invoked to report the [FrameTiming] of recently /// rasterized frames. /// /// It's preferred to use [SchedulerBinding.addTimingsCallback] than to use /// [onReportTimings] directly because [SchedulerBinding.addTimingsCallback] /// allows multiple callbacks. /// /// This can be used to see if the application has missed frames (through /// [FrameTiming.buildDuration] and [FrameTiming.rasterDuration]), or high /// latencies (through [FrameTiming.totalSpan]). /// /// Unlike [Timeline], the timing information here is available in the release /// mode (additional to the profile and the debug mode). Hence this can be /// used to monitor the application's performance in the wild. /// /// {@macro dart.ui.TimingsCallback.list} /// /// If this is null, no additional work will be done. If this is not null, /// Flutter spends less than 0.1ms every 1 second to report the timings /// (measured on iPhone6S). The 0.1ms is about 0.6% of 16ms (frame budget for /// 60fps), or 0.01% CPU usage per second. TimingsCallback? get onReportTimings => _onReportTimings; TimingsCallback? _onReportTimings; Zone _onReportTimingsZone = Zone.root; set onReportTimings(TimingsCallback? callback) { if ((callback == null) != (_onReportTimings == null)) { _setNeedsReportTimings(callback != null); } _onReportTimings = callback; _onReportTimingsZone = Zone.current; } late _SetNeedsReportTimingsFunc _setNeedsReportTimings; void _nativeSetNeedsReportTimings(bool value) => __nativeSetNeedsReportTimings(value); @Native(symbol: 'PlatformConfigurationNativeApi::SetNeedsReportTimings') external static void __nativeSetNeedsReportTimings(bool value); // Called from the engine, via hooks.dart void _reportTimings(List timings) { assert(timings.length % FrameTiming._dataLength == 0); final frameTimings = []; for (var i = 0; i < timings.length; i += FrameTiming._dataLength) { frameTimings.add(FrameTiming._(timings.sublist(i, i + FrameTiming._dataLength))); } _invoke1(onReportTimings, _onReportTimingsZone, frameTimings); } /// Sends a message to a platform-specific plugin. /// /// The `name` parameter determines which plugin receives the message. The /// `data` parameter contains the message payload and is typically UTF-8 /// encoded JSON but can be arbitrary data. If the plugin replies to the /// message, `callback` will be called with the response. /// /// The framework invokes [callback] in the same zone in which this method was /// called. void sendPlatformMessage(String name, ByteData? data, PlatformMessageResponseCallback? callback) { final String? error = _sendPlatformMessage( name, _zonedPlatformMessageResponseCallback(callback), data, ); if (error != null) { throw Exception(error); } } String? _sendPlatformMessage( String name, PlatformMessageResponseCallback? callback, ByteData? data, ) => __sendPlatformMessage(name, callback, data); @Native( symbol: 'PlatformConfigurationNativeApi::SendPlatformMessage', ) external static String? __sendPlatformMessage( String name, PlatformMessageResponseCallback? callback, ByteData? data, ); /// Sends a message to a platform-specific plugin via a [SendPort]. /// /// This operates similarly to [sendPlatformMessage] but is used when sending /// messages from background isolates. The [port] parameter allows Flutter to /// know which isolate to send the result to. The [name] parameter is the name /// of the channel communication will happen on. The [data] parameter is the /// payload of the message. The [identifier] parameter is a unique integer /// assigned to the message. void sendPortPlatformMessage(String name, ByteData? data, int identifier, SendPort port) { final String? error = _sendPortPlatformMessage(name, identifier, port.nativePort, data); if (error != null) { throw Exception(error); } } String? _sendPortPlatformMessage(String name, int identifier, int port, ByteData? data) => __sendPortPlatformMessage(name, identifier, port, data); @Native( symbol: 'PlatformConfigurationNativeApi::SendPortPlatformMessage', ) external static String? __sendPortPlatformMessage( String name, int identifier, int port, ByteData? data, ); /// Registers the current isolate with the isolate identified with by the /// [token]. This is required if platform channels are to be used on a /// background isolate. void registerBackgroundIsolate(RootIsolateToken token) { DartPluginRegistrant.ensureInitialized(); __registerBackgroundIsolate(token._token); } @Native(symbol: 'PlatformConfigurationNativeApi::RegisterBackgroundIsolate') external static void __registerBackgroundIsolate(int rootIsolateId); /// Informs the engine whether the framework is generating a semantics tree. /// /// Only framework knows when semantics tree should be generated. It uses this /// method to notify the engine whether the framework will generate a semantics tree. /// /// In the case where platforms want to enable semantics, e.g. when /// assistive technologies are enabled, it notifies framework through /// [onSemanticsEnabledChanged]. /// /// After this has been set to true, platforms are expected to prepare for accepting /// semantics update sent via [FlutterView.updateSemantics]. When this is set to false, platforms /// may dispose any resources associated with processing semantics as no further /// semantics updates will be sent via [FlutterView.updateSemantics]. /// /// One must call this method with true before sending update through [updateSemantics]. void setSemanticsTreeEnabled(bool enabled) => _setSemanticsTreeEnabled(enabled); @Native(symbol: 'PlatformConfigurationNativeApi::SetSemanticsTreeEnabled') external static void _setSemanticsTreeEnabled(bool update); /// Deprecated. Migrate to [ChannelBuffers.setListener] instead. /// /// Called whenever this platform dispatcher receives a message from a /// platform-specific plugin. /// /// The `name` parameter determines which plugin sent the message. The `data` /// parameter is the payload and is typically UTF-8 encoded JSON but can be /// arbitrary data. /// /// Message handlers must call the function given in the `callback` parameter. /// If the handler does not need to respond, the handler should pass null to /// the callback. /// /// The framework invokes this callback in the same zone in which the callback /// was set. @Deprecated( 'Migrate to ChannelBuffers.setListener instead. ' 'This feature was deprecated after v3.11.0-20.0.pre.', ) PlatformMessageCallback? get onPlatformMessage => _onPlatformMessage; PlatformMessageCallback? _onPlatformMessage; Zone _onPlatformMessageZone = Zone.root; @Deprecated( 'Migrate to ChannelBuffers.setListener instead. ' 'This feature was deprecated after v3.11.0-20.0.pre.', ) set onPlatformMessage(PlatformMessageCallback? callback) { _onPlatformMessage = callback; _onPlatformMessageZone = Zone.current; } /// Called by [_dispatchPlatformMessage]. void _respondToPlatformMessage(int responseId, ByteData? data) => __respondToPlatformMessage(responseId, data); @Native( symbol: 'PlatformConfigurationNativeApi::RespondToPlatformMessage', ) external static void __respondToPlatformMessage(int responseId, ByteData? data); /// Wraps the given [callback] in another callback that ensures that the /// original callback is called in the zone it was registered in. static PlatformMessageResponseCallback? _zonedPlatformMessageResponseCallback( PlatformMessageResponseCallback? callback, ) { if (callback == null) { return null; } // Store the zone in which the callback is being registered. final Zone registrationZone = Zone.current; return (ByteData? data) { registrationZone.runUnaryGuarded(callback, data); }; } /// Send a message to the framework using the [ChannelBuffers]. /// /// This method constructs the appropriate callback to respond /// with the given `responseId`. It should only be called for messages /// from the platform. void _dispatchPlatformMessage(String name, ByteData? data, int responseId) { if (name == ChannelBuffers.kControlChannelName) { try { channelBuffers.handleMessage(data!); } finally { _respondToPlatformMessage(responseId, null); } } else if (onPlatformMessage != null) { _invoke3( onPlatformMessage, _onPlatformMessageZone, name, data, (ByteData? responseData) { _respondToPlatformMessage(responseId, responseData); }, ); } else { channelBuffers.push(name, data, (ByteData? responseData) { _respondToPlatformMessage(responseId, responseData); }); } } /// Set the debug name associated with this platform dispatcher's root /// isolate. /// /// Normally debug names are automatically generated from the Dart port, entry /// point, and source file. For example: `main.dart$main-1234`. /// /// This can be combined with flutter tools `--isolate-filter` flag to debug /// specific root isolates. For example: `flutter attach --isolate-filter=[name]`. /// Note that this does not rename any child isolates of the root. void setIsolateDebugName(String name) => _setIsolateDebugName(name); @Native(symbol: 'PlatformConfigurationNativeApi::SetIsolateDebugName') external static void _setIsolateDebugName(String name); /// Requests the Dart VM to adjusts the GC heuristics based on the requested `performance_mode`. /// /// This operation is a no-op of web. The request to change a performance may be ignored by the /// engine or not resolve in a predictable way. /// /// See [DartPerformanceMode] for more information on individual performance modes. void requestDartPerformanceMode(DartPerformanceMode mode) { _requestDartPerformanceMode(mode.index); } @Native(symbol: 'PlatformConfigurationNativeApi::RequestDartPerformanceMode') external static int _requestDartPerformanceMode(int mode); /// The embedder can specify data that the isolate can request synchronously /// on launch. This accessor fetches that data. /// /// This data is persistent for the duration of the Flutter application and is /// available even after isolate restarts. Because of this lifecycle, the size /// of this data must be kept to a minimum. /// /// For asynchronous communication between the embedder and isolate, a /// platform channel may be used. ByteData? getPersistentIsolateData() => _getPersistentIsolateData(); @Native(symbol: 'PlatformConfigurationNativeApi::GetPersistentIsolateData') external static ByteData? _getPersistentIsolateData(); /// Requests that, at the next appropriate opportunity, the [onBeginFrame] and /// [onDrawFrame] callbacks be invoked. /// /// See also: /// /// * [SchedulerBinding], the Flutter framework class which manages the /// scheduling of frames. /// * [scheduleWarmUpFrame], which should only be used to schedule warm up /// frames. void scheduleFrame() => _scheduleFrame(); @Native(symbol: 'PlatformConfigurationNativeApi::ScheduleFrame') external static void _scheduleFrame(); /// Schedule a frame to run as soon as possible, rather than waiting for the /// engine to request a frame in response to a system "Vsync" signal. /// /// The application can call this method as soon as it starts up so that the /// first frame (which is likely to be quite expensive) can start a few extra /// milliseconds earlier. Using it in other situations might lead to /// unintended results, such as screen tearing. Depending on platforms and /// situations, the warm up frame might or might not be actually rendered onto /// the screen. /// /// For more introduction to the warm up frame, see /// [SchedulerBinding.scheduleWarmUpFrame]. /// /// This method uses the provided callbacks as the begin frame callback and /// the draw frame callback instead of [onBeginFrame] and [onDrawFrame]. /// /// See also: /// /// * [SchedulerBinding.scheduleWarmUpFrame], which uses this method, and /// introduces the warm up frame in more details. /// * [scheduleFrame], which schedules the frame at the next appropriate /// opportunity and should be used to render regular frames. void scheduleWarmUpFrame({required VoidCallback beginFrame, required VoidCallback drawFrame}) { // We use timers here to ensure that microtasks flush in between. Timer.run(beginFrame); Timer.run(() { drawFrame(); _endWarmUpFrame(); }); } @Native(symbol: 'PlatformConfigurationNativeApi::EndWarmUpFrame') external static void _endWarmUpFrame(); /// Additional accessibility features that may be enabled by the platform. AccessibilityFeatures get accessibilityFeatures => _configuration.accessibilityFeatures; /// A callback that is invoked when the value of [accessibilityFeatures] /// changes. /// /// The framework invokes this callback in the same zone in which the callback /// was set. VoidCallback? get onAccessibilityFeaturesChanged => _onAccessibilityFeaturesChanged; VoidCallback? _onAccessibilityFeaturesChanged; Zone _onAccessibilityFeaturesChangedZone = Zone.root; set onAccessibilityFeaturesChanged(VoidCallback? callback) { _onAccessibilityFeaturesChanged = callback; _onAccessibilityFeaturesChangedZone = Zone.current; } // Called from the engine, via hooks.dart void _updateAccessibilityFeatures(int values) { final newFeatures = AccessibilityFeatures._(values); final _PlatformConfiguration previousConfiguration = _configuration; if (newFeatures == previousConfiguration.accessibilityFeatures) { return; } _configuration = previousConfiguration.copyWith(accessibilityFeatures: newFeatures); _invoke(onPlatformConfigurationChanged, _onPlatformConfigurationChangedZone); _invoke(onAccessibilityFeaturesChanged, _onAccessibilityFeaturesChangedZone); } /// Change the retained semantics data about this platform dispatcher. /// /// If [semanticsEnabled] is true, the user has requested that this function /// be called whenever the semantic content of this platform dispatcher /// changes. /// /// In either case, this function disposes the given update, which means the /// semantics update cannot be used further. @Deprecated(''' In a multi-view world, the platform dispatcher can no longer provide apis to update semantics since each view will host its own semantics tree. Semantics updates must be passed to an individual [FlutterView]. To update semantics, use PlatformDispatcher.instance.views to get a [FlutterView] and call `updateSemantics`. ''') void updateSemantics(SemanticsUpdate update) => _updateSemantics(_implicitViewId!, update as _NativeSemanticsUpdate); @Native)>( symbol: 'PlatformConfigurationNativeApi::UpdateSemantics', ) external static void _updateSemantics(int viewId, _NativeSemanticsUpdate update); /// The system-reported default locale of the device. /// /// This establishes the language and formatting conventions that application /// should, if possible, use to render their user interface. /// /// This is the first locale selected by the user and is the user's primary /// locale (the locale the device UI is displayed in) /// /// This is equivalent to `locales.first`, except that it will provide an /// undefined (using the language tag "und") non-null locale if the [locales] /// list has not been set or is empty. Locale get locale => locales.isEmpty ? const Locale.fromSubtags() : locales.first; /// Sets the locale for the application in engine. /// /// This is typically called by framework to set the locale based on which /// locale the Flutter app actually uses. void setApplicationLocale(Locale locale) => _setApplicationLocale(locale.toLanguageTag()); @Native(symbol: 'PlatformConfigurationNativeApi::SetApplicationLocale') external static void _setApplicationLocale(String locale); /// The full system-reported supported locales of the device. /// /// This establishes the language and formatting conventions that application /// should, if possible, use to render their user interface. /// /// The list is ordered in order of priority, with lower-indexed locales being /// preferred over higher-indexed ones. The first element is the primary /// [locale]. /// /// The [onLocaleChanged] callback is called whenever this value changes. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this value changes. List get locales => _configuration.locales; /// Performs the platform-native locale resolution. /// /// Each platform may return different results. /// /// If the platform fails to resolve a locale, then this will return null. /// /// This method returns synchronously and is a direct call to /// platform specific APIs without invoking method channels. Locale? computePlatformResolvedLocale(List supportedLocales) { final supportedLocalesData = []; for (final locale in supportedLocales) { supportedLocalesData.add(locale.languageCode); supportedLocalesData.add(locale.countryCode); supportedLocalesData.add(locale.scriptCode); } final List result = _computePlatformResolvedLocale(supportedLocalesData); if (result.isNotEmpty) { return Locale.fromSubtags( languageCode: result[0], countryCode: result[1] == '' ? null : result[1], scriptCode: result[2] == '' ? null : result[2], ); } return null; } List _computePlatformResolvedLocale(List supportedLocalesData) => __computePlatformResolvedLocale(supportedLocalesData); @Native( symbol: 'PlatformConfigurationNativeApi::ComputePlatformResolvedLocale', ) external static List __computePlatformResolvedLocale(List supportedLocalesData); /// A callback that is invoked whenever [locale] changes value. /// /// The framework invokes this callback in the same zone in which the callback /// was set. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this callback is invoked. VoidCallback? get onLocaleChanged => _onLocaleChanged; VoidCallback? _onLocaleChanged; Zone _onLocaleChangedZone = Zone.root; set onLocaleChanged(VoidCallback? callback) { _onLocaleChanged = callback; _onLocaleChangedZone = Zone.current; } // Called from the engine, via hooks.dart void _updateLocales(List locales) { const stringsPerLocale = 4; final int numLocales = locales.length ~/ stringsPerLocale; final _PlatformConfiguration previousConfiguration = _configuration; final newLocales = []; var localesDiffer = numLocales != previousConfiguration.locales.length; for (var localeIndex = 0; localeIndex < numLocales; localeIndex++) { final String countryCode = locales[localeIndex * stringsPerLocale + 1]; final String scriptCode = locales[localeIndex * stringsPerLocale + 2]; newLocales.add( Locale.fromSubtags( languageCode: locales[localeIndex * stringsPerLocale], countryCode: countryCode.isEmpty ? null : countryCode, scriptCode: scriptCode.isEmpty ? null : scriptCode, ), ); if (!localesDiffer && newLocales[localeIndex] != previousConfiguration.locales[localeIndex]) { localesDiffer = true; } } if (!localesDiffer) { return; } _configuration = previousConfiguration.copyWith(locales: newLocales); _invoke(onPlatformConfigurationChanged, _onPlatformConfigurationChangedZone); _invoke(onLocaleChanged, _onLocaleChangedZone); } // Called from the engine, via hooks.dart String _localeClosure() => locale.toString(); /// The lifecycle state immediately after dart isolate initialization. /// /// This property will not be updated as the lifecycle changes. /// /// It is used to initialize [SchedulerBinding.lifecycleState] at startup with /// any buffered lifecycle state events. String get initialLifecycleState { _initialLifecycleStateAccessed = true; return _initialLifecycleState; } late String _initialLifecycleState; /// Tracks if the initial state has been accessed. Once accessed, we will stop /// updating the [initialLifecycleState], as it is not the preferred way to /// access the state. bool _initialLifecycleStateAccessed = false; // Called from the engine, via hooks.dart void _updateInitialLifecycleState(String state) { // We do not update the state if the state has already been used to initialize // the lifecycleState. if (!_initialLifecycleStateAccessed) { _initialLifecycleState = state; } } /// The setting indicating whether time should always be shown in the 24-hour /// format. /// /// This option is used by [showTimePicker]. bool get alwaysUse24HourFormat => _configuration.alwaysUse24HourFormat; /// The system-suggested height of the text, as a multiple of the font size. /// /// This value takes precedence over any text height specified at the /// application level. For example, at framework level, in the [TextStyle] /// for [Text], [SelectableText], and [EditableText] widgets, this value /// overrides the existing value of [TextStyle.height] and [StrutStyle.height]. /// /// Returns null when no override has been set by the system. /// /// If this value changes, [onMetricsChanged] will be called. double? get lineHeightScaleFactorOverride => _configuration.lineHeightScaleFactorOverride; /// The system-suggested amount of additional space (in logical pixels) /// to add between each letter. /// /// A negative value can be used to bring the letters closer. /// /// This value takes precedence over any text letter spacing specified at the /// application level. For example, at framework level, in the [TextStyle] /// for [Text], [SelectableText], and [EditableText] widgets, this value /// overrides the existing value of [TextStyle.letterSpacing]. /// /// Returns null when no override has been set by the system. /// /// If this value changes, [onMetricsChanged] will be called. double? get letterSpacingOverride => _configuration.letterSpacingOverride; /// The system-suggested amount of additional space (in logical pixels) /// to add between each sequence of white-space (i.e. between each word). /// /// A negative value can be used to bring the words closer. /// /// This value takes precedence over any text word spacing specified at the /// application level. For example, at framework level, in the [TextStyle] /// for [Text], [SelectableText], and [EditableText] widgets, this value /// overrides the existing value of [TextStyle.wordSpacing]. /// /// Returns null when no override has been set by the system. /// /// If this value changes, [onMetricsChanged] will be called. double? get wordSpacingOverride => _configuration.wordSpacingOverride; /// The system-suggested amount of additional space (in logical pixels) /// to add following each paragraph in text. /// /// This value takes precedence over any text paragraph spacing specified at /// the application level. /// /// Returns null when no override has been set by the system. /// /// If this value changes, [onMetricsChanged] will be called. double? get paragraphSpacingOverride => _configuration.paragraphSpacingOverride; /// The system-reported text scale. /// /// This establishes the text scaling factor to use when rendering text, /// according to the user's platform preferences. /// /// The [onTextScaleFactorChanged] callback is called whenever this value /// changes. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this value changes. double get textScaleFactor => _configuration.textScaleFactor; /// A callback that is invoked whenever [textScaleFactor] changes value. /// /// The framework invokes this callback in the same zone in which the callback /// was set. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this callback is invoked. VoidCallback? get onTextScaleFactorChanged => _onTextScaleFactorChanged; VoidCallback? _onTextScaleFactorChanged; Zone _onTextScaleFactorChangedZone = Zone.root; set onTextScaleFactorChanged(VoidCallback? callback) { _onTextScaleFactorChanged = callback; _onTextScaleFactorChangedZone = Zone.current; } /// Whether the spell check service is supported on the current platform. /// /// This option is used by [EditableTextState] to define its /// [SpellCheckConfiguration] when a default spell check service /// is requested. bool get nativeSpellCheckServiceDefined => _nativeSpellCheckServiceDefined; bool _nativeSpellCheckServiceDefined = false; /// Whether showing system context menu is supported on the current platform. /// /// This option is used by [AdaptiveTextSelectionToolbar] to decide whether /// to show system context menu, or to fallback to the default Flutter context /// menu. bool get supportsShowingSystemContextMenu => _supportsShowingSystemContextMenu; bool _supportsShowingSystemContextMenu = false; /// Whether briefly displaying the characters as you type in obscured text /// fields is enabled in system settings. /// /// See also: /// /// * [EditableText.obscureText], which when set to true hides the text in /// the text field. bool get brieflyShowPassword => _brieflyShowPassword; bool _brieflyShowPassword = true; /// The setting indicating the current brightness mode of the host platform. /// If the platform has no preference, [platformBrightness] defaults to /// [Brightness.light]. Brightness get platformBrightness => _configuration.platformBrightness; /// A callback that is invoked whenever [platformBrightness] changes value. /// /// The framework invokes this callback in the same zone in which the callback /// was set. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this callback is invoked. VoidCallback? get onPlatformBrightnessChanged => _onPlatformBrightnessChanged; VoidCallback? _onPlatformBrightnessChanged; Zone _onPlatformBrightnessChangedZone = Zone.root; set onPlatformBrightnessChanged(VoidCallback? callback) { _onPlatformBrightnessChanged = callback; _onPlatformBrightnessChangedZone = Zone.current; } /// The setting indicating the current system font of the host platform. String? get systemFontFamily => _configuration.systemFontFamily; /// A callback that is invoked whenever [systemFontFamily] changes value. /// /// The framework invokes this callback in the same zone in which the callback /// was set. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this callback is invoked. VoidCallback? get onSystemFontFamilyChanged => _onSystemFontFamilyChanged; VoidCallback? _onSystemFontFamilyChanged; Zone _onSystemFontFamilyChangedZone = Zone.root; set onSystemFontFamilyChanged(VoidCallback? callback) { _onSystemFontFamilyChanged = callback; _onSystemFontFamilyChangedZone = Zone.current; } // Called from the engine, via hooks.dart void _updateUserSettingsData(String jsonData) { final data = json.decode(jsonData) as Map; if (data.isEmpty) { return; } final double textScaleFactor = (data['textScaleFactor']! as num).toDouble(); final alwaysUse24HourFormat = data['alwaysUse24HourFormat']! as bool; final nativeSpellCheckServiceDefined = data['nativeSpellCheckServiceDefined'] as bool?; if (nativeSpellCheckServiceDefined != null) { _nativeSpellCheckServiceDefined = nativeSpellCheckServiceDefined; } else { _nativeSpellCheckServiceDefined = false; } final supportsShowingSystemContextMenu = data['supportsShowingSystemContextMenu'] as bool?; if (supportsShowingSystemContextMenu != null) { _supportsShowingSystemContextMenu = supportsShowingSystemContextMenu; } else { _supportsShowingSystemContextMenu = false; } // This field is optional. final brieflyShowPassword = data['brieflyShowPassword'] as bool?; if (brieflyShowPassword != null) { _brieflyShowPassword = brieflyShowPassword; } final Brightness platformBrightness = switch (data['platformBrightness']) { 'dark' => Brightness.dark, 'light' => Brightness.light, final Object? value => throw StateError('$value is not a valid platformBrightness.'), }; final systemFontFamily = data['systemFontFamily'] as String?; final configurationId = data['configurationId'] as int?; final _PlatformConfiguration previousConfiguration = _configuration; final platformBrightnessChanged = previousConfiguration.platformBrightness != platformBrightness; final textScaleFactorChanged = previousConfiguration.textScaleFactor != textScaleFactor; final alwaysUse24HourFormatChanged = previousConfiguration.alwaysUse24HourFormat != alwaysUse24HourFormat; final systemFontFamilyChanged = previousConfiguration.systemFontFamily != systemFontFamily; if (!platformBrightnessChanged && !textScaleFactorChanged && !alwaysUse24HourFormatChanged && !systemFontFamilyChanged && configurationId == null) { return; } _configuration = previousConfiguration.copyWith( textScaleFactor: textScaleFactor, alwaysUse24HourFormat: alwaysUse24HourFormat, platformBrightness: platformBrightness, systemFontFamily: systemFontFamily, configurationId: configurationId, ); _invoke(onPlatformConfigurationChanged, _onPlatformConfigurationChangedZone); if (textScaleFactorChanged) { _cachedFontSizes = null; _invoke(onTextScaleFactorChanged, _onTextScaleFactorChangedZone); } if (platformBrightnessChanged) { _invoke(onPlatformBrightnessChanged, _onPlatformBrightnessChangedZone); } if (systemFontFamilyChanged) { _invoke(onSystemFontFamilyChanged, _onSystemFontFamilyChangedZone); } } /// Whether the user has requested that updateSemantics be called when the /// semantic contents of a view changes. /// /// The [onSemanticsEnabledChanged] callback is called whenever this value /// changes. bool get semanticsEnabled => _configuration.semanticsEnabled; /// A callback that is invoked when the value of [semanticsEnabled] changes. /// /// The framework invokes this callback in the same zone in which the /// callback was set. VoidCallback? get onSemanticsEnabledChanged => _onSemanticsEnabledChanged; VoidCallback? _onSemanticsEnabledChanged; Zone _onSemanticsEnabledChangedZone = Zone.root; set onSemanticsEnabledChanged(VoidCallback? callback) { _onSemanticsEnabledChanged = callback; _onSemanticsEnabledChangedZone = Zone.current; } // Called from the engine, via hooks.dart void _updateSemanticsEnabled(bool enabled) { final _PlatformConfiguration previousConfiguration = _configuration; if (previousConfiguration.semanticsEnabled == enabled) { return; } _configuration = previousConfiguration.copyWith(semanticsEnabled: enabled); _invoke(onPlatformConfigurationChanged, _onPlatformConfigurationChangedZone); _invoke(onSemanticsEnabledChanged, _onSemanticsEnabledChangedZone); } /// A callback that is invoked whenever the user requests an action to be /// performed on a semantics node. /// /// This callback is used when the user expresses the action they wish to /// perform based on the semantics node supplied by updateSemantics. /// /// The framework invokes this callback in the same zone in which the /// callback was set. SemanticsActionEventCallback? get onSemanticsActionEvent => _onSemanticsActionEvent; SemanticsActionEventCallback? _onSemanticsActionEvent; Zone _onSemanticsActionEventZone = Zone.root; set onSemanticsActionEvent(SemanticsActionEventCallback? callback) { _onSemanticsActionEvent = callback; _onSemanticsActionEventZone = Zone.current; } // Called from the engine via hooks.dart. void _updateFrameData(int frameNumber) { final FrameData previous = _frameData; if (previous.frameNumber == frameNumber) { return; } _frameData = FrameData._(frameNumber: frameNumber); _invoke(onFrameDataChanged, _onFrameDataChangedZone); } /// The [FrameData] object for the current frame. FrameData get frameData => _frameData; FrameData _frameData = const FrameData._(); /// A callback that is invoked when the window updates the [FrameData]. VoidCallback? get onFrameDataChanged => _onFrameDataChanged; VoidCallback? _onFrameDataChanged; Zone _onFrameDataChangedZone = Zone.root; set onFrameDataChanged(VoidCallback? callback) { _onFrameDataChanged = callback; _onFrameDataChangedZone = Zone.current; } // Called from the engine, via hooks.dart void _dispatchSemanticsAction(int viewId, int nodeId, int action, ByteData? args) { _invoke1( onSemanticsActionEvent, _onSemanticsActionEventZone, SemanticsActionEvent( type: SemanticsAction.fromIndex(action)!, nodeId: nodeId, viewId: viewId, arguments: args, ), ); } ErrorCallback? _onError; Zone? _onErrorZone; /// A callback that is invoked when an unhandled error occurs in the root /// isolate. /// /// This callback must return `true` if it has handled the error. Otherwise, /// it must return `false` and a fallback mechanism such as printing to stderr /// will be used, as configured by the specific platform embedding via /// `Settings::unhandled_exception_callback`. /// /// The VM or the process may exit or become unresponsive after calling this /// callback. The callback will not be called for exceptions that cause the VM /// or process to terminate or become unresponsive before the callback can be /// invoked. /// /// This callback is not directly invoked by errors in child isolates of the /// root isolate. Programs that create new isolates must listen for errors on /// those isolates and forward the errors to the root isolate. ErrorCallback? get onError => _onError; set onError(ErrorCallback? callback) { _onError = callback; _onErrorZone = Zone.current; } bool _dispatchError(Object error, StackTrace stackTrace) { if (_onError == null) { return false; } assert(_onErrorZone != null); if (identical(_onErrorZone, Zone.current)) { return _onError!(error, stackTrace); } else { try { return _onErrorZone!.runBinary(_onError!, error, stackTrace); } catch (e, s) { _onErrorZone!.handleUncaughtError(e, s); return false; } } } /// The route or path that the embedder requested when the application was /// launched. /// /// This will be the string "`/`" if no particular route was requested. /// /// ## Android /// /// On Android, calling /// [`FlutterView.setInitialRoute`](/javadoc/io/flutter/view/FlutterView.html#setInitialRoute-java.lang.String-) /// will set this value. The value must be set sufficiently early, i.e. before /// the [runApp] call is executed in Dart, for this to have any effect on the /// framework. The `createFlutterView` method in your `FlutterActivity` /// subclass is a suitable time to set the value. The application's /// `AndroidManifest.xml` file must also be updated to have a suitable /// [``](https://developer.android.com/guide/topics/manifest/intent-filter-element.html). /// /// ## iOS /// /// On iOS, calling /// [`FlutterViewController.setInitialRoute`](/ios-embedder/interface_flutter_view_controller.html#a7f269c2da73312f856d42611cc12a33f) /// will set this value. The value must be set sufficiently early, i.e. before /// the [runApp] call is executed in Dart, for this to have any effect on the /// framework. The `application:didFinishLaunchingWithOptions:` method is a /// suitable time to set this value. /// /// See also: /// /// * [Navigator], a widget that handles routing. /// * [SystemChannels.navigation], which handles subsequent navigation /// requests from the embedder. String get defaultRouteName => _defaultRouteName(); @Native(symbol: 'PlatformConfigurationNativeApi::DefaultRouteName') external static String _defaultRouteName(); /// Computes the scaled font size from the given `unscaledFontSize`, according /// to the user's platform preferences. /// /// Many platforms allow users to scale text globally for better readability. /// Given the font size the app developer specified in logical pixels, this /// method converts it to the preferred font size (also in logical pixels) that /// accounts for platform-wide text scaling. The return value is always /// non-negative. /// /// The scaled value of the same font size input may change if the user changes /// the text scaling preference (in system settings for example). The /// [onTextScaleFactorChanged] callback can be used to monitor such changes. /// /// Instead of directly calling this method, applications should typically use /// [MediaQuery.textScalerOf] to retrive the scaled font size in a widget tree, /// so text in the app resizes properly when the text scaling preference /// changes. double scaleFontSize(double unscaledFontSize) { assert(unscaledFontSize >= 0); assert(unscaledFontSize.isFinite); if (textScaleFactor == 1.0) { return unscaledFontSize; } final int unscaledFloor = unscaledFontSize.floor(); final int unscaledCeil = unscaledFontSize.ceil(); if (unscaledFloor == unscaledCeil) { // No need to interpolate if the input value is an integer. return _scaleAndMemoize(unscaledFloor) ?? unscaledFontSize * textScaleFactor; } assert( unscaledCeil - unscaledFloor == 1, 'Unexpected interpolation range: $unscaledFloor - $unscaledCeil.', ); return switch ((_scaleAndMemoize(unscaledFloor), _scaleAndMemoize(unscaledCeil))) { (null, _) || (_, null) => unscaledFontSize * textScaleFactor, (final double lower, final double upper) => lower + (upper - lower) * (unscaledFontSize - unscaledFloor), }; } // The cache is cleared when the text scale factor changes. Map? _cachedFontSizes; // This method returns null if an error is encountered. double? _scaleAndMemoize(int unscaledFontSize) { final int? configurationId = _configuration.configurationId; if (configurationId == null) { // The platform uses linear scaling, or the platform hasn't sent us a // configuration yet. return null; } final double? cachedValue = _cachedFontSizes?[unscaledFontSize]; if (cachedValue != null) { assert(cachedValue >= 0); return cachedValue; } final double unscaledFontSizeDouble = unscaledFontSize.toDouble(); final double fontSize = PlatformDispatcher._getScaledFontSize( unscaledFontSizeDouble, configurationId, ); if (fontSize >= 0) { return (_cachedFontSizes ??= {})[unscaledFontSize] = fontSize; } switch (fontSize) { case -1: // Invalid configuration id. This error can be unrecoverable as the // _getScaledFontSize function can be destructive. assert(false, 'Flutter Error: incorrect configuration id: $configurationId.'); case final double errorCode: assert(false, 'Unknown error: GetScaledFontSize failed with $errorCode.'); } return null; } // Calls the platform's text scaling implementation to scale the given // `unscaledFontSize`. // // The `configurationId` parameter tells the embedder which platform // configuration to use for computing the scaled font size. When the user // changes the platform configuration, the configuration data will first be // made available on the platform thread before being dispatched asynchronously // to the Flutter UI thread. Since this call is synchronous, without this // identifier, it could call into the embber who's using a newer configuration // that Flutter has not received yet. The `configurationId` parameter must be // the lastest configuration id received from the platform // (`_configuration.configurationId`). Using an incorrect id could result in // an unrecoverable error. // // Currently this is only implemented on newer versions of Android (SDK level // 34, using the `TypedValue#applyDimension` API). Platforms that do not have // the capability will never send a `configurationId` to [PlatformDispatcher], // and should not call this method. This method returns -1 when the specified // configurationId does not match any configuration. @Native(symbol: 'PlatformConfigurationNativeApi::GetScaledFontSize') external static double _getScaledFontSize(double unscaledFontSize, int configurationId); } /// A color specified in the operating system UI color palette. /// /// As of the current release, system colors are supported on web only. To check /// if the current platform supports system colors, use the static /// [platformProvidesSystemColors] field. If the field is `false`, other /// functions in this class will throw [UnsupportedError]. /// /// This class is typically used in conjunction with /// [AccessibilityFeatures.highContrast]. In particular, on Windows, when a user /// enables high-contrast mode, they may also pick specific colors that should /// be used by application user interfaces. While it is common for applications /// to use custom color themes and design languages, in high-contrast mode it is /// recommended that widgets use system-specified colors to make content more /// legible for users. /// /// The "light" system colors are available through [SystemColor.light], and the "dark" system /// colors are available through [SystemColor.dark]. /// /// Example: /// /// ```dart /// import 'dart:ui'; /// /// Color getSystemAccentColor() { /// Color? systemAccentColor; /// if (SystemColor.platformProvidesSystemColors) { /// if (PlatformDispatcher.instance.platformBrightness == Brightness.light) { /// systemAccentColor = SystemColor.light.accentColor.value; /// } else { /// systemAccentColor = SystemColor.dark.accentColor.value; /// } /// } /// /// return systemAccentColor ?? const Color(0xFF007AFF); /// } /// ``` /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors /// * https://developer.mozilla.org/en-US/docs/Web/CSS/system-color /// * https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors final class SystemColor { /// Creates an instance of a system color. /// /// [name] is the name of the color. System colors provided by [SystemColorPalette], such as /// [SystemColorPalette.accentColor] and [SystemColorPalette.buttonText], use standard names /// defined by the [W3C CSS specification](https://drafts.csswg.org/css-color/#css-system-colors). /// /// [value] is the color value, if this color name is supported, and null if /// it's unsupported. const SystemColor({required this.name, this.value}); /// Standard system color name, as defined by W3C CSS specification. /// /// System color names in Flutter are case-sensitive. This is so that color /// names can be easily used as [Map] keys. This is in contrast to CSS, where /// system color names are not case-sensitive. That is, specifying /// `background-color: aCcEnTcOlOr` is equivalent to specifying /// `background-color: AccentColor`. /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors final String name; /// The color value used for the color named [name], if supported. /// /// If [isSupported] is false, the [value] is null. If [isSupported] is true, /// the [value] is not null. final Color? value; /// Returns true if the current platform provides the system color with the /// given [name]. /// /// See also: /// /// * [platformProvidesSystemColors], which returns whether the current /// platform provides system colors. bool get isSupported => value != null; /// Returns true if the current platform provides system colors. /// /// As of the current release, system colors are supported on web only. /// /// See also: /// /// * [isSupported], which returns whether a specific color is supported. static bool get platformProvidesSystemColors => false; /// A palette of system colors for light mode. static final SystemColorPalette light = SystemColorPalette._(Brightness.light); /// A palette of system colors for dark mode. static final SystemColorPalette dark = SystemColorPalette._(Brightness.dark); } /// A palette of system colors specified in the operating system for a given [brightness]. /// /// The getters in this class, such as [accentColor] and [buttonText], provide standard system /// colors defined by the [W3C CSS specification](https://drafts.csswg.org/css-color/#css-system-colors). final class SystemColorPalette { SystemColorPalette._(this.brightness); /// The brightness mode for which this palette is defined. final Brightness brightness; static UnsupportedError _systemColorUnsupportedError() { return UnsupportedError('SystemColor not supported on the current platform.'); } /// Returns system color named "AccentColor". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get accentColor => throw _systemColorUnsupportedError(); /// Returns system color named "AccentColorText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get accentColorText => throw _systemColorUnsupportedError(); /// Returns system color named "ActiveText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get activeText => throw _systemColorUnsupportedError(); /// Returns system color named "ButtonBorder". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get buttonBorder => throw _systemColorUnsupportedError(); /// Returns system color named "ButtonFace". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get buttonFace => throw _systemColorUnsupportedError(); /// Returns system color named "ButtonText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get buttonText => throw _systemColorUnsupportedError(); /// Returns system color named "Canvas". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get canvas => throw _systemColorUnsupportedError(); /// Returns system color named "CanvasText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get canvasText => throw _systemColorUnsupportedError(); /// Returns system color named "Field". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get field => throw _systemColorUnsupportedError(); /// Returns system color named "FieldText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get fieldText => throw _systemColorUnsupportedError(); /// Returns system color named "GrayText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get grayText => throw _systemColorUnsupportedError(); /// Returns system color named "Highlight". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get highlight => throw _systemColorUnsupportedError(); /// Returns system color named "HighlightText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get highlightText => throw _systemColorUnsupportedError(); /// Returns system color named "LinkText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get linkText => throw _systemColorUnsupportedError(); /// Returns system color named "Mark". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get mark => throw _systemColorUnsupportedError(); /// Returns system color named "MarkText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get markText => throw _systemColorUnsupportedError(); /// Returns system color named "SelectedItem". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get selectedItem => throw _systemColorUnsupportedError(); /// Returns system color named "SelectedItemText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get selectedItemText => throw _systemColorUnsupportedError(); /// Returns system color named "VisitedText". /// /// See also: /// /// * https://drafts.csswg.org/css-color/#css-system-colors SystemColor get visitedText => throw _systemColorUnsupportedError(); } /// Configuration of the platform. /// /// Immutable class (but can't use @immutable in dart:ui) class _PlatformConfiguration { const _PlatformConfiguration({ this.accessibilityFeatures = const AccessibilityFeatures._(0), this.alwaysUse24HourFormat = false, this.semanticsEnabled = false, this.platformBrightness = Brightness.light, this.textScaleFactor = 1.0, this.locales = const [], this.defaultRouteName, this.systemFontFamily, this.configurationId, this.lineHeightScaleFactorOverride, this.letterSpacingOverride, this.wordSpacingOverride, this.paragraphSpacingOverride, }); _PlatformConfiguration copyWith({ AccessibilityFeatures? accessibilityFeatures, bool? alwaysUse24HourFormat, bool? semanticsEnabled, Brightness? platformBrightness, double? textScaleFactor, List? locales, String? defaultRouteName, String? systemFontFamily, int? configurationId, }) { return _PlatformConfiguration( accessibilityFeatures: accessibilityFeatures ?? this.accessibilityFeatures, alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat, semanticsEnabled: semanticsEnabled ?? this.semanticsEnabled, platformBrightness: platformBrightness ?? this.platformBrightness, textScaleFactor: textScaleFactor ?? this.textScaleFactor, locales: locales ?? this.locales, defaultRouteName: defaultRouteName ?? this.defaultRouteName, systemFontFamily: systemFontFamily ?? this.systemFontFamily, configurationId: configurationId ?? this.configurationId, lineHeightScaleFactorOverride: lineHeightScaleFactorOverride, letterSpacingOverride: letterSpacingOverride, wordSpacingOverride: wordSpacingOverride, paragraphSpacingOverride: paragraphSpacingOverride, ); } /// Additional accessibility features that may be enabled by the platform. final AccessibilityFeatures accessibilityFeatures; /// The setting indicating whether time should always be shown in the 24-hour /// format. final bool alwaysUse24HourFormat; /// Whether the user has requested that updateSemantics be called when the /// semantic contents of a view changes. final bool semanticsEnabled; /// The setting indicating the current brightness mode of the host platform. /// If the platform has no preference, [platformBrightness] defaults to /// [Brightness.light]. final Brightness platformBrightness; /// The system-reported text scale. final double textScaleFactor; /// The full system-reported supported locales of the device. final List locales; /// The route or path that the embedder requested when the application was /// launched. final String? defaultRouteName; /// The system-reported default font family. final String? systemFontFamily; /// A unique identifier for this [_PlatformConfiguration]. /// /// This unique identifier is optionally assigned by the platform embedder. /// Dart code that runs on the Flutter UI thread and synchronously invokes /// platform APIs can use this identifier to tell the embedder to use the /// configuration that matches the current [_PlatformConfiguration] in /// dart:ui. See the [_getScaledFontSize] function for an example. /// /// This field's nullability also indicates whether the platform supports /// nonlinear text scaling (as it's the only feature that requires synchronous /// invocation of platform APIs). This field is always null if the platform /// does not use nonlinear text scaling, or when dart:ui has not received any /// configuration updates from the embedder yet. The _getScaledFontSize /// function should not be called in either case. final int? configurationId; /// The system-reported height of the text, as a multiple of the font size. final double? lineHeightScaleFactorOverride; /// The system-reported amount of additional space (in logical pixels) /// to add between each letter. /// /// A negative value can be used to bring the letters closer. final double? letterSpacingOverride; /// The system-reported amount of additional space (in logical pixels) /// to add between each sequence of white-space (i.e. between each word). /// /// A negative value can be used to bring the words closer. final double? wordSpacingOverride; /// The system-reported amount of additional space (in logical pixels) /// to add between each paragraph in text. final double? paragraphSpacingOverride; } /// An immutable view configuration. class _ViewConfiguration { const _ViewConfiguration({ this.devicePixelRatio = 1.0, this.size = Size.zero, this.viewInsets = ViewPadding.zero, this.viewPadding = ViewPadding.zero, this.systemGestureInsets = ViewPadding.zero, this.padding = ViewPadding.zero, this.gestureSettings = const GestureSettings(), this.displayFeatures = const [], this.displayId = 0, this.viewConstraints = const ViewConstraints(maxWidth: 0, maxHeight: 0), }); /// The identifier for a display for this view, in /// [PlatformDispatcher._displays]. final int displayId; /// The sizing constraints for this view in physical pixels. final ViewConstraints viewConstraints; /// The pixel density of the output surface. final double devicePixelRatio; /// The size requested for the view in physical pixels. final Size size; /// The number of physical pixels on each side of the display rectangle into /// which the view can render, but over which the operating system will likely /// place system UI, such as the keyboard, that fully obscures any content. /// /// The relationship between this [viewInsets], [viewPadding], and [padding] /// are described in more detail in the documentation for [FlutterView]. final ViewPadding viewInsets; /// The number of physical pixels on each side of the display rectangle into /// which the view can render, but which may be partially obscured by system /// UI (such as the system notification area), or physical intrusions in /// the display (e.g. overscan regions on television screens or phone sensor /// housings). /// /// Unlike [padding], this value does not change relative to [viewInsets]. /// For example, on an iPhone X, it will not change in response to the soft /// keyboard being visible or hidden, whereas [padding] will. /// /// The relationship between this [viewInsets], [viewPadding], and [padding] /// are described in more detail in the documentation for [FlutterView]. final ViewPadding viewPadding; /// The number of physical pixels on each side of the display rectangle into /// which the view can render, but where the operating system will consume /// input gestures for the sake of system navigation. /// /// For example, an operating system might use the vertical edges of the /// screen, where swiping inwards from the edges takes users backward /// through the history of screens they previously visited. final ViewPadding systemGestureInsets; /// The number of physical pixels on each side of the display rectangle into /// which the view can render, but which may be partially obscured by system /// UI (such as the system notification area), or physical intrusions in /// the display (e.g. overscan regions on television screens or phone sensor /// housings). /// /// The relationship between this [viewInsets], [viewPadding], and [padding] /// are described in more detail in the documentation for [FlutterView]. final ViewPadding padding; /// Additional configuration for touch gestures performed on this view. /// /// For example, the touch slop defined in physical pixels may be provided /// by the gesture settings and should be preferred over the framework /// touch slop constant. final GestureSettings gestureSettings; /// Areas of the display that are obstructed by hardware features. /// /// This list is populated only on Android. If the device has no display /// features, this list is empty. /// /// The coordinate space in which the [DisplayFeature.bounds] are defined spans /// across the screens currently in use. This means that the space between the screens /// is virtually part of the Flutter view space, with the [DisplayFeature.bounds] /// of the display feature as an obstructed area. The [DisplayFeature.type] can /// be used to determine if this display feature obstructs the screen or not. /// For example, [DisplayFeatureType.hinge] and [DisplayFeatureType.cutout] both /// obstruct the display, while [DisplayFeatureType.fold] is a crease in the display. /// /// Folding [DisplayFeature]s like the [DisplayFeatureType.hinge] and /// [DisplayFeatureType.fold] also have a [DisplayFeature.state] which can be /// used to determine the posture the device is in. final List displayFeatures; @override String toString() { return '$runtimeType[size: $size]'; } } /// Various important time points in the lifetime of a frame. /// /// [FrameTiming] records a timestamp of each phase for performance analysis. enum FramePhase { /// The timestamp of the vsync signal given by the operating system. /// /// See also [FrameTiming.vsyncOverhead]. vsyncStart, /// When the UI thread starts building a frame. /// /// See also [FrameTiming.buildDuration]. buildStart, /// When the UI thread finishes building a frame. /// /// See also [FrameTiming.buildDuration]. buildFinish, /// When the raster thread starts rasterizing a frame. /// /// See also [FrameTiming.rasterDuration]. rasterStart, /// When the raster thread finishes rasterizing a frame. /// /// See also [FrameTiming.rasterDuration]. rasterFinish, /// When the raster thread finished rasterizing a frame in wall-time. /// /// This is useful for correlating time raster finish time with the system /// clock to integrate with other profiling tools. rasterFinishWallTime, } enum _FrameTimingInfo { /// The number of engine layers cached in the raster cache during the frame. layerCacheCount, /// The number of bytes used to cache engine layers during the frame. layerCacheBytes, /// The number of picture layers cached in the raster cache during the frame. pictureCacheCount, /// The number of bytes used to cache pictures during the frame. pictureCacheBytes, /// The frame number of the frame. frameNumber, } /// Time-related performance metrics of a frame. /// /// If you're using the whole Flutter framework, please use /// [SchedulerBinding.addTimingsCallback] to get this. It's preferred over using /// [PlatformDispatcher.onReportTimings] directly because /// [SchedulerBinding.addTimingsCallback] allows multiple callbacks. If /// [SchedulerBinding] is unavailable, then see [PlatformDispatcher.onReportTimings] /// for how to get this. /// /// The metrics in debug mode (`flutter run` without any flags) may be very /// different from those in profile and release modes due to the debug overhead. /// Therefore it's recommended to only monitor and analyze performance metrics /// in profile and release modes. class FrameTiming { /// Construct [FrameTiming] with raw timestamps in microseconds. /// /// This constructor is used for unit test only. Real [FrameTiming]s should /// be retrieved from [PlatformDispatcher.onReportTimings]. /// /// If the [frameNumber] is not provided, it defaults to `-1`. factory FrameTiming({ required int vsyncStart, required int buildStart, required int buildFinish, required int rasterStart, required int rasterFinish, required int rasterFinishWallTime, int layerCacheCount = 0, int layerCacheBytes = 0, int pictureCacheCount = 0, int pictureCacheBytes = 0, int frameNumber = -1, }) { return FrameTiming._([ vsyncStart, buildStart, buildFinish, rasterStart, rasterFinish, rasterFinishWallTime, layerCacheCount, layerCacheBytes, pictureCacheCount, pictureCacheBytes, frameNumber, ]); } /// Construct [FrameTiming] with raw timestamps in microseconds. /// /// List [timestamps] must have the same number of elements as /// [FramePhase.values]. /// /// This constructor is usually only called by the Flutter engine, or a test. /// To get the [FrameTiming] of your app, see [PlatformDispatcher.onReportTimings]. FrameTiming._(this._data) : assert(_data.length == _dataLength); static final int _dataLength = FramePhase.values.length + _FrameTimingInfo.values.length; /// This is a raw timestamp in microseconds from some epoch. The epoch in all /// [FrameTiming] is the same, but it may not match [DateTime]'s epoch. int timestampInMicroseconds(FramePhase phase) => _data[phase.index]; Duration _rawDuration(FramePhase phase) => Duration(microseconds: _data[phase.index]); int _rawInfo(_FrameTimingInfo info) => _data[FramePhase.values.length + info.index]; /// The duration to build the frame on the UI thread. /// /// The build starts approximately when [PlatformDispatcher.onBeginFrame] is /// called. The [Duration] in the [PlatformDispatcher.onBeginFrame] callback /// is exactly the `Duration(microseconds: /// timestampInMicroseconds(FramePhase.buildStart))`. /// /// The build finishes when [FlutterView.render] is called. /// /// {@template dart.ui.FrameTiming.fps_smoothness_milliseconds} /// To ensure smooth animations of X fps, this should not exceed 1000/X /// milliseconds. /// {@endtemplate} /// {@template dart.ui.FrameTiming.fps_milliseconds} /// That's about 16ms for 60fps, and 8ms for 120fps. /// {@endtemplate} Duration get buildDuration => _rawDuration(FramePhase.buildFinish) - _rawDuration(FramePhase.buildStart); /// The duration to rasterize the frame on the raster thread. /// /// {@macro dart.ui.FrameTiming.fps_smoothness_milliseconds} /// {@macro dart.ui.FrameTiming.fps_milliseconds} Duration get rasterDuration => _rawDuration(FramePhase.rasterFinish) - _rawDuration(FramePhase.rasterStart); /// The duration between receiving the vsync signal and starting building the /// frame. Duration get vsyncOverhead => _rawDuration(FramePhase.buildStart) - _rawDuration(FramePhase.vsyncStart); /// The timespan between vsync start and raster finish. /// /// To achieve the lowest latency on an X fps display, this should not exceed /// 1000/X milliseconds. /// {@macro dart.ui.FrameTiming.fps_milliseconds} /// /// See also [vsyncOverhead], [buildDuration] and [rasterDuration]. Duration get totalSpan => _rawDuration(FramePhase.rasterFinish) - _rawDuration(FramePhase.vsyncStart); /// The number of layers stored in the raster cache during the frame. /// /// See also [layerCacheBytes], [pictureCacheCount] and [pictureCacheBytes]. int get layerCacheCount => _rawInfo(_FrameTimingInfo.layerCacheCount); /// The number of bytes of image data used to cache layers during the frame. /// /// See also [layerCacheCount], [layerCacheMegabytes], [pictureCacheCount] and [pictureCacheBytes]. int get layerCacheBytes => _rawInfo(_FrameTimingInfo.layerCacheBytes); /// The number of megabytes of image data used to cache layers during the frame. /// /// See also [layerCacheCount], [layerCacheBytes], [pictureCacheCount] and [pictureCacheBytes]. double get layerCacheMegabytes => layerCacheBytes / 1024.0 / 1024.0; /// The number of pictures stored in the raster cache during the frame. /// /// See also [layerCacheCount], [layerCacheBytes] and [pictureCacheBytes]. int get pictureCacheCount => _rawInfo(_FrameTimingInfo.pictureCacheCount); /// The number of bytes of image data used to cache pictures during the frame. /// /// See also [layerCacheCount], [layerCacheBytes], [pictureCacheCount] and [pictureCacheMegabytes]. int get pictureCacheBytes => _rawInfo(_FrameTimingInfo.pictureCacheBytes); /// The number of megabytes of image data used to cache pictures during the frame. /// /// See also [layerCacheCount], [layerCacheBytes], [pictureCacheCount] and [pictureCacheBytes]. double get pictureCacheMegabytes => pictureCacheBytes / 1024.0 / 1024.0; /// The frame key associated with this frame measurement. int get frameNumber => _data.last; final List _data; // some elements in microseconds, some in bytes, some are counts String _formatMS(Duration duration) => '${duration.inMicroseconds * 0.001}ms'; @override String toString() { return '$runtimeType(buildDuration: ${_formatMS(buildDuration)}, ' 'rasterDuration: ${_formatMS(rasterDuration)}, ' 'vsyncOverhead: ${_formatMS(vsyncOverhead)}, ' 'totalSpan: ${_formatMS(totalSpan)}, ' 'layerCacheCount: $layerCacheCount, ' 'layerCacheBytes: $layerCacheBytes, ' 'pictureCacheCount: $pictureCacheCount, ' 'pictureCacheBytes: $pictureCacheBytes, ' 'frameNumber: ${_data.last})'; } } /// States that an application can be in once it is running. /// /// States not supported on a platform will be synthesized by the framework when /// transitioning between states which are supported, so that all /// implementations share the same state machine. /// /// The initial value for the state is the [detached] state, updated to the /// current state (usually [resumed]) as soon as the first lifecycle update is /// received from the platform. /// /// For historical and name collision reasons, Flutter's application state names /// do not correspond one to one with the state names on all platforms. On /// Android, for instance, when the OS calls /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause()), /// Flutter will enter the [inactive] state, but when Android calls /// [`Activity.onStop`](https://developer.android.com/reference/android/app/Activity#onStop()), /// Flutter enters the [paused] state. See the individual state's documentation /// for descriptions of what they mean on each platform. /// /// The current application state can be obtained from /// [SchedulerBinding.instance.lifecycleState], and changes to the state can be /// observed by creating an [AppLifecycleListener], or by using a /// [WidgetsBindingObserver] by overriding the /// [WidgetsBindingObserver.didChangeAppLifecycleState] method. /// /// Applications should not rely on always receiving all possible notifications. /// /// For example, if the application is killed with a task manager, a kill /// signal, the user pulls the power from the device, or there is a rapid /// unscheduled disassembly of the device, no notification will be sent before /// the application is suddenly terminated, and some states may be skipped. /// /// See also: /// /// * [AppLifecycleListener], an object used observe the lifecycle state that /// provides state transition callbacks. /// * [WidgetsBindingObserver], for a mechanism to observe the lifecycle state /// from the widgets layer. /// * iOS's [UIKit activity /// lifecycle](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle?language=objc) /// documentation. /// * Android's [activity /// lifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle) /// documentation. /// * macOS's [AppKit activity /// lifecycle](https://developer.apple.com/documentation/appkit/nsapplicationdelegate?language=objc) /// documentation. enum AppLifecycleState { /// The application is still hosted by a Flutter engine but is detached from /// any host views. /// /// The application defaults to this state before it initializes, and can be /// in this state (applicable on Android, iOS, and web) after all views have been /// detached. /// /// When the application is in this state, the engine is running without a /// view. /// /// This state is only entered on iOS, Android, and web, although on all platforms /// it is the default state before the application begins running. detached, /// On all platforms, this state indicates that the application is in the /// default running mode for a running application that has input focus and is /// visible. /// /// On Android, this state corresponds to the Flutter host view having focus /// ([`Activity.onWindowFocusChanged`](https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)) /// was called with true) while in Android's "resumed" state. It is possible /// for the Flutter app to be in the [inactive] state while still being in /// Android's /// ["onResume"](https://developer.android.com/guide/components/activities/activity-lifecycle) /// state if the app has lost focus /// ([`Activity.onWindowFocusChanged`](https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)) /// was called with false), but hasn't had /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause()) /// called on it. /// /// On iOS and macOS, this corresponds to the app running in the foreground /// active state. resumed, /// At least one view of the application is visible, but none have input /// focus. The application is otherwise running normally. /// /// On non-web desktop platforms, this corresponds to an application that is /// not in the foreground, but still has visible windows. /// /// On the web, this corresponds to an application that is running in a /// window or tab that does not have input focus. /// /// On iOS and macOS, this state corresponds to the Flutter host view running in the /// foreground inactive state. Apps transition to this state when in a phone /// call, when responding to a TouchID request, when entering the app switcher /// or the control center, or when the UIViewController hosting the Flutter /// app is transitioning. /// /// On Android, this corresponds to the Flutter host view running in Android's /// paused state (i.e. /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause()) /// has been called), or in Android's "resumed" state (i.e. /// [`Activity.onResume`](https://developer.android.com/reference/android/app/Activity#onResume()) /// has been called) but does not have window focus. Examples of when apps /// transition to this state include when the app is partially obscured or /// another activity is focused, a app running in a split screen that isn't /// the current app, an app interrupted by a phone call, a picture-in-picture /// app, a system dialog, another view. It will also be inactive when the /// notification window shade is down, or the application switcher is visible. /// /// On Android and iOS, apps in this state should assume that they may be /// [hidden] and [paused] at any time. inactive, /// All views of an application are hidden, either because the application is /// about to be paused (on iOS and Android), or because it has been minimized /// or placed on a desktop that is no longer visible (on non-web desktop), or /// is running in a window or tab that is no longer visible (on the web). /// /// On iOS and Android, in order to keep the state machine the same on all /// platforms, a transition to this state is synthesized before the [paused] /// state is entered when coming from [inactive], and before the [inactive] /// state is entered when coming from [paused]. This allows cross-platform /// implementations that want to know when an app is conceptually "hidden" to /// only write one handler. hidden, /// The application is not currently visible to the user, and not responding /// to user input. /// /// When the application is in this state, the engine will not call the /// [PlatformDispatcher.onBeginFrame] and [PlatformDispatcher.onDrawFrame] /// callbacks. /// /// This state is only entered on iOS and Android. paused, } /// The possible responses to a request to exit the application. /// /// The request is typically responded to by creating an [AppLifecycleListener] /// and supplying an [AppLifecycleListener.onExitRequested] callback, or by /// overriding [WidgetsBindingObserver.didRequestAppExit]. enum AppExitResponse { /// Exiting the application can proceed. exit, /// Cancel the exit: do not exit the application. cancel, } /// The type of application exit to perform when calling /// [ServicesBinding.exitApplication]. enum AppExitType { /// Requests that the application start an orderly exit, sending a request /// back to the framework through the [WidgetsBinding]. If that responds /// with [AppExitResponse.exit], then proceed with the same steps as a /// [required] exit. If that responds with [AppExitResponse.cancel], then the /// exit request is canceled and the application continues executing normally. cancelable, /// A non-cancelable orderly exit request. The engine will shut down the /// engine and call the native UI toolkit's exit API. /// /// If you need an even faster and more dangerous exit, then call `dart:io`'s /// `exit()` directly, and even the native toolkit's exit API won't be called. /// This is quite dangerous, though, since it's possible that the engine will /// crash because it hasn't been properly shut down, causing the app to crash /// on exit. required, } /// A representation of distances for each of the four edges of a rectangle, /// used to encode the view insets and padding that applications should place /// around their user interface, as exposed by [FlutterView.viewInsets] and /// [FlutterView.padding]. View insets and padding are preferably read via /// [MediaQuery.of]. /// /// For a generic class that represents distances around a rectangle, see the /// [EdgeInsets] class. /// /// See also: /// /// * [WidgetsBindingObserver], for a widgets layer mechanism to receive /// notifications when the padding changes. /// * [MediaQuery.of], for the preferred mechanism for accessing these values. /// * [Scaffold], which automatically applies the padding in material design /// applications. class ViewPadding { const ViewPadding._({ required this.left, required this.top, required this.right, required this.bottom, }); /// The distance from the left edge to the first unpadded pixel, in physical pixels. final double left; /// The distance from the top edge to the first unpadded pixel, in physical pixels. final double top; /// The distance from the right edge to the first unpadded pixel, in physical pixels. final double right; /// The distance from the bottom edge to the first unpadded pixel, in physical pixels. final double bottom; /// A view padding that has zeros for each edge. static const ViewPadding zero = ViewPadding._(left: 0.0, top: 0.0, right: 0.0, bottom: 0.0); @override String toString() { return 'ViewPadding(left: $left, top: $top, right: $right, bottom: $bottom)'; } } /// Deprecated. Will be removed in a future version of Flutter. /// /// Use [ViewPadding] instead. @Deprecated( 'Use ViewPadding instead. ' 'This feature was deprecated after v3.8.0-14.0.pre.', ) typedef WindowPadding = ViewPadding; /// Immutable layout constraints for [FlutterView]s. /// /// Similar to [BoxConstraints], a [Size] respects a [ViewConstraints] if, and /// only if, all of the following relations hold: /// /// * [minWidth] <= [Size.width] <= [maxWidth] /// * [minHeight] <= [Size.height] <= [maxHeight] /// /// The constraints themselves must satisfy these relations: /// /// * 0.0 <= [minWidth] <= [maxWidth] <= [double.infinity] /// * 0.0 <= [minHeight] <= [maxHeight] <= [double.infinity] /// /// For each constraint, [double.infinity] is a legal value. /// /// For a generic class that represents these kind of constraints, see the /// [BoxConstraints] class. class ViewConstraints { /// Creates view constraints with the given constraints. const ViewConstraints({ this.minWidth = 0.0, this.maxWidth = double.infinity, this.minHeight = 0.0, this.maxHeight = double.infinity, }); /// Creates view constraints that is respected only by the given size. ViewConstraints.tight(Size size) : minWidth = size.width, maxWidth = size.width, minHeight = size.height, maxHeight = size.height; /// The minimum width that satisfies the constraints. final double minWidth; /// The maximum width that satisfies the constraints. /// /// Might be [double.infinity]. final double maxWidth; /// The minimum height that satisfies the constraints. final double minHeight; /// The maximum height that satisfies the constraints. /// /// Might be [double.infinity]. final double maxHeight; /// Whether the given size satisfies the constraints. bool isSatisfiedBy(Size size) { return (minWidth <= size.width) && (size.width <= maxWidth) && (minHeight <= size.height) && (size.height <= maxHeight); } /// Whether there is exactly one size that satisfies the constraints. bool get isTight => minWidth >= maxWidth && minHeight >= maxHeight; /// Scales each constraint parameter by the inverse of the given factor. ViewConstraints operator /(double factor) { return ViewConstraints( minWidth: minWidth / factor, maxWidth: maxWidth / factor, minHeight: minHeight / factor, maxHeight: maxHeight / factor, ); } @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is ViewConstraints && other.minWidth == minWidth && other.maxWidth == maxWidth && other.minHeight == minHeight && other.maxHeight == maxHeight; } @override int get hashCode => Object.hash(minWidth, maxWidth, minHeight, maxHeight); @override String toString() { if (minWidth == double.infinity && minHeight == double.infinity) { return 'ViewConstraints(biggest)'; } if (minWidth == 0 && maxWidth == double.infinity && minHeight == 0 && maxHeight == double.infinity) { return 'ViewConstraints(unconstrained)'; } String describe(double min, double max, String dim) { if (min == max) { return '$dim=${min.toStringAsFixed(1)}'; } return '${min.toStringAsFixed(1)}<=$dim<=${max.toStringAsFixed(1)}'; } final String width = describe(minWidth, maxWidth, 'w'); final String height = describe(minHeight, maxHeight, 'h'); return 'ViewConstraints($width, $height)'; } } /// Area of the display that may be obstructed by a hardware feature. /// /// This is populated only on Android. /// /// The [bounds] are measured in logical pixels. On devices with two screens the /// coordinate system starts with (0,0) in the top-left corner of the left or top screen /// and expands to include both screens and the visual space between them. /// /// The [type] describes the behaviour and if [DisplayFeature] obstructs the display. /// For example, [DisplayFeatureType.hinge] and [DisplayFeatureType.cutout] both obstruct the display, /// while [DisplayFeatureType.fold] does not. /// /// ![Device with a hinge display feature](https://flutter.github.io/assets-for-api-docs/assets/hardware/display_feature_hinge.png) /// /// ![Device with a fold display feature](https://flutter.github.io/assets-for-api-docs/assets/hardware/display_feature_fold.png) /// /// ![Device with a cutout display feature](https://flutter.github.io/assets-for-api-docs/assets/hardware/display_feature_cutout.png) /// /// The [state] contains information about the posture for foldable features /// ([DisplayFeatureType.hinge] and [DisplayFeatureType.fold]). The posture is /// the shape of the display, for example [DisplayFeatureState.postureFlat] or /// [DisplayFeatureState.postureHalfOpened]. For [DisplayFeatureType.cutout], /// the state is not used and has the [DisplayFeatureState.unknown] value. class DisplayFeature { // TODO(matanlurey): have original authors document; see https://github.com/flutter/flutter/issues/151917. // ignore: public_member_api_docs const DisplayFeature({required this.bounds, required this.type, required this.state}) : assert( !identical(type, DisplayFeatureType.cutout) || identical(state, DisplayFeatureState.unknown), ); /// The area of the flutter view occupied by this display feature, measured in logical pixels. /// /// On devices with two screens, the Flutter view spans from the top-left corner /// of the left or top screen to the bottom-right corner of the right or bottom screen, /// including the visual area occupied by any display feature. Bounds of display /// features are reported in this coordinate system. /// /// For example, on a dual screen device in portrait mode: /// /// * [Rect.left] gives you the size of left screen, in logical pixels. /// * [Rect.right] gives you the size of the left screen + the hinge width. final Rect bounds; /// Type of display feature, e.g. hinge, fold, cutout. final DisplayFeatureType type; /// Posture of display feature, which is populated only for folds and hinges. /// /// For cutouts, this is [DisplayFeatureState.unknown] final DisplayFeatureState state; @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is DisplayFeature && bounds == other.bounds && type == other.type && state == other.state; } @override int get hashCode => Object.hash(bounds, type, state); @override String toString() { return 'DisplayFeature(rect: $bounds, type: $type, state: $state)'; } } /// Type of [DisplayFeature], describing the [DisplayFeature] behaviour and if /// it obstructs the display. /// /// Some types of [DisplayFeature], like [DisplayFeatureType.fold], can be /// reported without actually impeding drawing on the screen. They are useful /// for knowing where the display is bent or has a crease. The /// [DisplayFeature.bounds] can be 0-width in such cases. /// /// The shape formed by the screens for types [DisplayFeatureType.fold] and /// [DisplayFeatureType.hinge] is called the posture and is exposed in /// [DisplayFeature.state]. For example, the [DisplayFeatureState.postureFlat] posture /// means the screens form a flat surface. /// /// ![Device with a hinge display feature](https://flutter.github.io/assets-for-api-docs/assets/hardware/display_feature_hinge.png) /// /// ![Device with a fold display feature](https://flutter.github.io/assets-for-api-docs/assets/hardware/display_feature_fold.png) /// /// ![Device with a cutout display feature](https://flutter.github.io/assets-for-api-docs/assets/hardware/display_feature_cutout.png) enum DisplayFeatureType { /// [DisplayFeature] type is new and not yet known to Flutter. unknown, /// A fold in the flexible screen without a physical gap. /// /// The bounds for this display feature type indicate where the display makes a crease. fold, /// A physical separation with a hinge that allows two display panels to fold. hinge, /// A non-displaying area of the screen, usually housing cameras or sensors. cutout, } /// State of the display feature, which contains information about the posture /// for foldable features. /// /// The posture is the shape made by the parts of the flexible screen or /// physical screen panels. They are inspired by and similar to /// [Android Postures](https://developer.android.com/guide/topics/ui/foldables#postures). /// /// * For [DisplayFeatureType.fold]s & [DisplayFeatureType.hinge]s, the state is /// the posture. /// * For [DisplayFeatureType.cutout]s, the state is not used and has the /// [DisplayFeatureState.unknown] value. enum DisplayFeatureState { /// The display feature is a [DisplayFeatureType.cutout] or this state is new /// and not yet known to Flutter. unknown, /// The foldable device is completely open. /// /// The screen space that is presented to the user is flat. postureFlat, /// Fold angle is in an intermediate position between opened and closed state. /// /// There is a non-flat angle between parts of the flexible screen or between /// physical screen panels such that the screens start to face each other. postureHalfOpened, } /// An identifier used to select a user's language and formatting preferences. /// /// This represents a [Unicode Language /// Identifier](https://www.unicode.org/reports/tr35/#Unicode_language_identifier) /// (i.e. without Locale extensions), except variants are not supported. /// /// Locales are canonicalized according to the "preferred value" entries in the /// [IANA Language Subtag /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry). /// For example, `const Locale('he')` and `const Locale('iw')` are equal and /// both have the [languageCode] `he`, because `iw` is a deprecated language /// subtag that was replaced by the subtag `he`. /// /// See also: /// /// * [PlatformDispatcher.locale], which specifies the system's currently selected /// [Locale]. class Locale { /// Creates a new Locale object. The first argument is the /// primary language subtag, the second is the region (also /// referred to as 'country') subtag. /// /// For example: /// /// ```dart /// const Locale swissFrench = Locale('fr', 'CH'); /// const Locale canadianFrench = Locale('fr', 'CA'); /// ``` /// /// The primary language subtag must not be null. The region subtag is /// optional. When there is no region/country subtag, the parameter should /// be omitted or passed `null` instead of an empty-string. /// /// The subtag values are _case sensitive_ and must be one of the valid /// subtags according to CLDR supplemental data: /// [language](https://github.com/unicode-org/cldr/blob/master/common/validity/language.xml), /// [region](https://github.com/unicode-org/cldr/blob/master/common/validity/region.xml). The /// primary language subtag must be at least two and at most eight lowercase /// letters, but not four letters. The region subtag must be two /// uppercase letters or three digits. See the [Unicode Language /// Identifier](https://www.unicode.org/reports/tr35/#Unicode_language_identifier) /// specification. /// /// Validity is not checked by default, but some methods may throw away /// invalid data. /// /// See also: /// /// * [Locale.fromSubtags], which also allows a [scriptCode] to be /// specified. const Locale(this._languageCode, [this._countryCode]) : assert(_languageCode != ''), scriptCode = null; /// Creates a new Locale object. /// /// The keyword arguments specify the subtags of the Locale. /// /// The subtag values are _case sensitive_ and must be valid subtags according /// to CLDR supplemental data: /// [language](https://github.com/unicode-org/cldr/blob/master/common/validity/language.xml), /// [script](https://github.com/unicode-org/cldr/blob/master/common/validity/script.xml) and /// [region](https://github.com/unicode-org/cldr/blob/master/common/validity/region.xml) for /// each of languageCode, scriptCode and countryCode respectively. /// /// The [languageCode] subtag is optional. When there is no language subtag, /// the parameter should be omitted or set to "und". When not supplied, the /// [languageCode] defaults to "und", an undefined language code. /// /// The [countryCode] subtag is optional. When there is no country subtag, /// the parameter should be omitted or passed `null` instead of an empty-string. /// /// Validity is not checked by default, but some methods may throw away /// invalid data. const Locale.fromSubtags({String languageCode = 'und', this.scriptCode, String? countryCode}) : assert(languageCode != ''), _languageCode = languageCode, assert(scriptCode != ''), assert(countryCode != ''), _countryCode = countryCode; /// The primary language subtag for the locale. /// /// This must not be null. It may be 'und', representing 'undefined'. /// /// This is expected to be string registered in the [IANA Language Subtag /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry) /// with the type "language". The string specified must match the case of the /// string in the registry. /// /// Language subtags that are deprecated in the registry and have a preferred /// code are changed to their preferred code. For example, `const /// Locale('he')` and `const Locale('iw')` are equal, and both have the /// [languageCode] `he`, because `iw` is a deprecated language subtag that was /// replaced by the subtag `he`. /// /// This must be a valid Unicode Language subtag as listed in [Unicode CLDR /// supplemental /// data](https://github.com/unicode-org/cldr/blob/master/common/validity/language.xml). /// /// See also: /// /// * [Locale.fromSubtags], which describes the conventions for creating /// [Locale] objects. String get languageCode => _deprecatedLanguageSubtagMap[_languageCode] ?? _languageCode; final String _languageCode; // This map is generated by //flutter/tools/gen_locale.dart // Mappings generated for language subtag registry as of 2019-02-27. static const Map _deprecatedLanguageSubtagMap = { 'in': 'id', // Indonesian; deprecated 1989-01-01 'iw': 'he', // Hebrew; deprecated 1989-01-01 'ji': 'yi', // Yiddish; deprecated 1989-01-01 'jw': 'jv', // Javanese; deprecated 2001-08-13 'mo': 'ro', // Moldavian, Moldovan; deprecated 2008-11-22 'aam': 'aas', // Aramanik; deprecated 2015-02-12 'adp': 'dz', // Adap; deprecated 2015-02-12 'aue': 'ktz', // ǂKxʼauǁʼein; deprecated 2015-02-12 'ayx': 'nun', // Ayi (China); deprecated 2011-08-16 'bgm': 'bcg', // Baga Mboteni; deprecated 2016-05-30 'bjd': 'drl', // Bandjigali; deprecated 2012-08-12 'ccq': 'rki', // Chaungtha; deprecated 2012-08-12 'cjr': 'mom', // Chorotega; deprecated 2010-03-11 'cka': 'cmr', // Khumi Awa Chin; deprecated 2012-08-12 'cmk': 'xch', // Chimakum; deprecated 2010-03-11 'coy': 'pij', // Coyaima; deprecated 2016-05-30 'cqu': 'quh', // Chilean Quechua; deprecated 2016-05-30 'drh': 'khk', // Darkhat; deprecated 2010-03-11 'drw': 'prs', // Darwazi; deprecated 2010-03-11 'gav': 'dev', // Gabutamon; deprecated 2010-03-11 'gfx': 'vaj', // Mangetti Dune ǃXung; deprecated 2015-02-12 'ggn': 'gvr', // Eastern Gurung; deprecated 2016-05-30 'gti': 'nyc', // Gbati-ri; deprecated 2015-02-12 'guv': 'duz', // Gey; deprecated 2016-05-30 'hrr': 'jal', // Horuru; deprecated 2012-08-12 'ibi': 'opa', // Ibilo; deprecated 2012-08-12 'ilw': 'gal', // Talur; deprecated 2013-09-10 'jeg': 'oyb', // Jeng; deprecated 2017-02-23 'kgc': 'tdf', // Kasseng; deprecated 2016-05-30 'kgh': 'kml', // Upper Tanudan Kalinga; deprecated 2012-08-12 'koj': 'kwv', // Sara Dunjo; deprecated 2015-02-12 'krm': 'bmf', // Krim; deprecated 2017-02-23 'ktr': 'dtp', // Kota Marudu Tinagas; deprecated 2016-05-30 'kvs': 'gdj', // Kunggara; deprecated 2016-05-30 'kwq': 'yam', // Kwak; deprecated 2015-02-12 'kxe': 'tvd', // Kakihum; deprecated 2015-02-12 'kzj': 'dtp', // Coastal Kadazan; deprecated 2016-05-30 'kzt': 'dtp', // Tambunan Dusun; deprecated 2016-05-30 'lii': 'raq', // Lingkhim; deprecated 2015-02-12 'lmm': 'rmx', // Lamam; deprecated 2014-02-28 'meg': 'cir', // Mea; deprecated 2013-09-10 'mst': 'mry', // Cataelano Mandaya; deprecated 2010-03-11 'mwj': 'vaj', // Maligo; deprecated 2015-02-12 'myt': 'mry', // Sangab Mandaya; deprecated 2010-03-11 'nad': 'xny', // Nijadali; deprecated 2016-05-30 'ncp': 'kdz', // Ndaktup; deprecated 2018-03-08 'nnx': 'ngv', // Ngong; deprecated 2015-02-12 'nts': 'pij', // Natagaimas; deprecated 2016-05-30 'oun': 'vaj', // ǃOǃung; deprecated 2015-02-12 'pcr': 'adx', // Panang; deprecated 2013-09-10 'pmc': 'huw', // Palumata; deprecated 2016-05-30 'pmu': 'phr', // Mirpur Panjabi; deprecated 2015-02-12 'ppa': 'bfy', // Pao; deprecated 2016-05-30 'ppr': 'lcq', // Piru; deprecated 2013-09-10 'pry': 'prt', // Pray 3; deprecated 2016-05-30 'puz': 'pub', // Purum Naga; deprecated 2014-02-28 'sca': 'hle', // Sansu; deprecated 2012-08-12 'skk': 'oyb', // Sok; deprecated 2017-02-23 'tdu': 'dtp', // Tempasuk Dusun; deprecated 2016-05-30 'thc': 'tpo', // Tai Hang Tong; deprecated 2016-05-30 'thx': 'oyb', // The; deprecated 2015-02-12 'tie': 'ras', // Tingal; deprecated 2011-08-16 'tkk': 'twm', // Takpa; deprecated 2011-08-16 'tlw': 'weo', // South Wemale; deprecated 2012-08-12 'tmp': 'tyj', // Tai Mène; deprecated 2016-05-30 'tne': 'kak', // Tinoc Kallahan; deprecated 2016-05-30 'tnf': 'prs', // Tangshewi; deprecated 2010-03-11 'tsf': 'taj', // Southwestern Tamang; deprecated 2015-02-12 'uok': 'ema', // Uokha; deprecated 2015-02-12 'xba': 'cax', // Kamba (Brazil); deprecated 2016-05-30 'xia': 'acn', // Xiandao; deprecated 2013-09-10 'xkh': 'waw', // Karahawyana; deprecated 2016-05-30 'xsj': 'suj', // Subi; deprecated 2015-02-12 'ybd': 'rki', // Yangbye; deprecated 2012-08-12 'yma': 'lrr', // Yamphe; deprecated 2012-08-12 'ymt': 'mtm', // Mator-Taygi-Karagas; deprecated 2015-02-12 'yos': 'zom', // Yos; deprecated 2013-09-10 'yuu': 'yug', // Yugh; deprecated 2014-02-28 }; /// The script subtag for the locale. /// /// This may be null, indicating that there is no specified script subtag. /// /// This must be a valid Unicode Language Identifier script subtag as listed /// in [Unicode CLDR supplemental /// data](https://github.com/unicode-org/cldr/blob/master/common/validity/script.xml). /// /// See also: /// /// * [Locale.fromSubtags], which describes the conventions for creating /// [Locale] objects. final String? scriptCode; /// The region subtag for the locale. /// /// This may be null, indicating that there is no specified region subtag. /// /// This is expected to be string registered in the [IANA Language Subtag /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry) /// with the type "region". The string specified must match the case of the /// string in the registry. /// /// Region subtags that are deprecated in the registry and have a preferred /// code are changed to their preferred code. For example, `const Locale('de', /// 'DE')` and `const Locale('de', 'DD')` are equal, and both have the /// [countryCode] `DE`, because `DD` is a deprecated language subtag that was /// replaced by the subtag `DE`. /// /// See also: /// /// * [Locale.fromSubtags], which describes the conventions for creating /// [Locale] objects. String? get countryCode => _deprecatedRegionSubtagMap[_countryCode] ?? _countryCode; final String? _countryCode; // This map is generated by //flutter/tools/gen_locale.dart // Mappings generated for language subtag registry as of 2019-02-27. static const Map _deprecatedRegionSubtagMap = { 'BU': 'MM', // Burma; deprecated 1989-12-05 'DD': 'DE', // German Democratic Republic; deprecated 1990-10-30 'FX': 'FR', // Metropolitan France; deprecated 1997-07-14 'TP': 'TL', // East Timor; deprecated 2002-05-20 'YD': 'YE', // Democratic Yemen; deprecated 1990-08-14 'ZR': 'CD', // Zaire; deprecated 1997-07-14 }; @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other is! Locale) { return false; } final String? thisCountryCode = countryCode; final String? otherCountryCode = other.countryCode; return other.languageCode == languageCode && other.scriptCode == scriptCode // scriptCode cannot be '' && (other.countryCode == thisCountryCode // Treat '' as equal to null. || otherCountryCode != null && otherCountryCode.isEmpty && thisCountryCode == null || thisCountryCode != null && thisCountryCode.isEmpty && other.countryCode == null); } @override int get hashCode => Object.hash(languageCode, scriptCode, countryCode == '' ? null : countryCode); static Locale? _cachedLocale; static String? _cachedLocaleString; /// Returns a string representing the locale. /// /// This identifier happens to be a valid Unicode Locale Identifier using /// underscores as separator, however it is intended to be used for debugging /// purposes only. For parsable results, use [toLanguageTag] instead. @keepToString @override String toString() { if (!identical(_cachedLocale, this)) { _cachedLocale = this; _cachedLocaleString = _rawToString('_'); } return _cachedLocaleString!; } /// Returns a syntactically valid Unicode BCP47 Locale Identifier. /// /// Some examples of such identifiers: "en", "es-419", "hi-Deva-IN" and /// "zh-Hans-CN". See http://www.unicode.org/reports/tr35/ for technical /// details. String toLanguageTag() => _rawToString('-'); String _rawToString(String separator) { final out = StringBuffer(languageCode); if (scriptCode != null && scriptCode!.isNotEmpty) { out.write('$separator$scriptCode'); } final String? countryCode = _countryCode; if (countryCode != null && countryCode.isNotEmpty) { out.write('$separator${this.countryCode}'); } return out.toString(); } } /// Various performance modes for tuning the Dart VM's GC performance. /// /// For the editor of this enum, please keep the order in sync with `Dart_PerformanceMode` /// in [dart_api.h](https://github.com/dart-lang/sdk/blob/main/runtime/include/dart_api.h#L1302). enum DartPerformanceMode { /// This is the default mode that the Dart VM is in. balanced, /// Optimize for low latency, at the expense of throughput and memory overhead /// by performing work in smaller batches (requiring more overhead) or by /// delaying work (requiring more memory). An embedder should not remain in /// this mode indefinitely. latency, /// Optimize for high throughput, at the expense of latency and memory overhead /// by performing work in larger batches with more intervening growth. throughput, /// Optimize for low memory, at the expensive of throughput and latency by more /// frequently performing work. memory, } /// An event to request a [SemanticsAction] of [type] to be performed on the /// [SemanticsNode] identified by [nodeId] owned by the [FlutterView] identified /// by [viewId]. /// /// Used by [SemanticsBinding.performSemanticsAction]. class SemanticsActionEvent { /// Creates a [SemanticsActionEvent]. const SemanticsActionEvent({ required this.type, required this.viewId, required this.nodeId, this.arguments, }); /// The type of action to be performed. final SemanticsAction type; /// The id of the [FlutterView] the [SemanticsNode] identified by [nodeId] is /// associated with. final int viewId; /// The id of the [SemanticsNode] on which the action is to be performed. final int nodeId; /// Optional arguments for the action. final Object? arguments; static const Object _noArgumentPlaceholder = Object(); /// Create a clone of the [SemanticsActionEvent] but with provided parameters /// replaced. SemanticsActionEvent copyWith({ SemanticsAction? type, int? viewId, int? nodeId, Object? arguments = _noArgumentPlaceholder, }) { return SemanticsActionEvent( type: type ?? this.type, viewId: viewId ?? this.viewId, nodeId: nodeId ?? this.nodeId, arguments: arguments == _noArgumentPlaceholder ? this.arguments : arguments, ); } } /// Signature for [PlatformDispatcher.onViewFocusChange]. typedef ViewFocusChangeCallback = void Function(ViewFocusEvent viewFocusEvent); /// An event for the engine to communicate view focus changes to the app. /// /// This value will be typically passed to the [PlatformDispatcher.onViewFocusChange] /// callback. final class ViewFocusEvent { /// Creates a [ViewFocusChange]. const ViewFocusEvent({required this.viewId, required this.state, required this.direction}); /// The ID of the [FlutterView] that experienced a focus change. final int viewId; /// The state focus changed to. final ViewFocusState state; /// The direction focus changed to. final ViewFocusDirection direction; @override String toString() { return 'ViewFocusEvent(viewId: $viewId, state: $state, direction: $direction)'; } } /// Represents the focus state of a given [FlutterView]. /// /// When focus is lost, the view's focus state changes to [ViewFocusState.unfocused]. /// /// When focus is gained, the view's focus state changes to [ViewFocusState.focused]. /// /// Valid transitions within a view are: /// /// - [ViewFocusState.focused] to [ViewFocusState.unfocused]. /// - [ViewFocusState.unfocused] to [ViewFocusState.focused]. /// /// See also: /// /// * [ViewFocusDirection], that specifies the focus direction. /// * [ViewFocusEvent], that conveys information about a [FlutterView] focus change. enum ViewFocusState { /// Specifies that a view does not have platform focus. unfocused, /// Specifies that a view has platform focus. focused, } /// Represents the direction in which the focus transitioned across [FlutterView]s. /// /// See also: /// /// * [ViewFocusState], that specifies the current focus state of a [FlutterView]. /// * [ViewFocusEvent], that conveys information about a [FlutterView] focus change. enum ViewFocusDirection { /// Indicates the focus transition did not have a direction. /// /// This is typically associated with focus being programmatically requested or /// when focus is lost. undefined, /// Indicates the focus transition was performed in a forward direction. /// /// This is typically result of the user pressing tab. forward, /// Indicates the focus transition was performed in a backward direction. /// /// This is typically result of the user pressing shift + tab. backward, }