blob: ab2c917920378a2a08d22cf879378e41d2ba0b14 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:fidl_fuchsia_ui_views/fidl_async.dart';
// ignore_for_file: public_member_api_docs, unnecessary_null_comparison
typedef ChildViewConnectionCallback = void Function(
ChildViewConnection connection);
typedef ChildViewConnectionStateCallback = void Function(
ChildViewConnection connection, bool? newState);
/// A connection to a child view. It can be used to construct a [ChildView]
/// widget that will display the view's contents on their own layer.
class ChildViewConnection {
/// [ViewHolderToken] of the child view.
final ViewHolderToken viewHolderToken;
/// The optional [ViewRef] of the view.
final ViewRef? viewRef;
/// Callback when the connection to child's view is established.
final ChildViewConnectionCallback? onAvailable;
/// Callback when the child's view is disconnected.
final ChildViewConnectionCallback? onUnavailable;
/// Callback when the child view's state changes.
final ChildViewConnectionStateCallback? onStateChanged;
/// Whether to use [PlatformView] feature of Flutter.
bool usePlatformView;
/// SceneHost used to reference and render content from a remote Scene.
SceneHost? get sceneHost => _sceneHost;
SceneHost? _sceneHost;
final _platformViewChannel = MethodChannel(
'flutter/platform_views',
JSONMethodCodec(),
);
/// Creates this connection from a ViewHolderToken.
ChildViewConnection(
this.viewHolderToken, {
this.viewRef,
this.onAvailable,
this.onUnavailable,
this.onStateChanged,
this.usePlatformView = false,
}) : assert(viewHolderToken.value != null && viewHolderToken.value.isValid),
assert(
viewRef?.reference == null || viewRef!.reference.handle!.isValid) {
if (!usePlatformView) {
_sceneHost = SceneHost(
viewHolderToken.value.passHandle(),
(onAvailable == null)
? null
: () {
onAvailable!(this);
},
(onUnavailable == null)
? null
: () {
onUnavailable!(this);
},
(onStateChanged == null)
? null
: (bool state) {
onStateChanged!(this, state);
});
} else {
try {
_platformViewChannel.setMethodCallHandler((call) async {
switch (call.method) {
case 'View.viewConnected':
onAvailable?.call(this);
break;
case 'View.viewDisconnected':
onUnavailable?.call(this);
break;
case 'View.viewStateChanged':
onStateChanged?.call(this, call.arguments['state'] ?? false);
break;
default:
print('Unknown method call from platform view channel: $call');
}
});
} on Exception catch (e) {
print('Failed to set method call handler: $e');
}
}
}
/// Gets the view id from [viewHolderToken].
int get viewId => viewHolderToken.value.handle!.handle;
/// Releases native resources held by [SceneHost] object in Flutter engine.
void dispose() {
if (usePlatformView) {
final args = <String, dynamic>{'viewId': viewId};
_platformViewChannel.invokeMethod('View.dispose', args);
} else {
_sceneHost!.dispose();
_sceneHost = null;
}
}
/// Called by [ChildViewRenderBox2] when the platform view is ready to
/// be initialized.
Future<void> connect({bool? hitTestable, bool? focusable}) async {
final args = <String, dynamic>{
'viewId': viewId,
'hitTestable': hitTestable,
'focusable': focusable,
};
await _platformViewChannel.invokeMethod('View.create', args);
}
/// Requests that focus be transferred to the remote Scene represented by
/// this connection.
Future<void> requestFocus() async {
assert(viewRef != null);
final args = <String, dynamic>{
'viewRef': viewRef!.reference.handle!.handle
};
final result =
await _platformViewChannel.invokeMethod('View.requestFocus', args);
// Throw OSError if result is non-zero.
if (result != 0) {
final koid = viewRef!.reference.handle!.koid;
final error = Error(result);
throw OSError(
'Failed to request focus for view: $koid with $error',
result,
);
}
}
/// Sets properties on the remote Scene represented by this connection.
void setChildProperties(double width, double height, double insetTop,
double insetRight, double insetBottom, double insetLeft,
{bool focusable = true}) {
_sceneHost?.setProperties(
width, height, insetTop, insetRight, insetBottom, insetLeft, focusable);
}
/// Sets properties on the remote Scene represented by this connection.
///
/// Called by [ChildViewRenderBox2] when the [focusable] and [hitTestable]
/// properties are changed.
void setViewProperties({bool? focusable = true, bool? hitTestable = true}) {
final args = <String, dynamic>{
'viewId': viewId,
'hitTestable': hitTestable,
'focusable': focusable,
};
_platformViewChannel.invokeMethod('View.update', args);
}
}