blob: 86497fe7bf265d05b3b2f0f2229bf650e8c25034 [file] [log] [blame]
// Copyright 2014 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.
import 'dart:async';
import 'package:flutter/services.dart';
import 'plugin_registry.dart';
/// A named channel for sending events to the framework-side using streams.
///
/// This is the platform-side equivalent of [EventChannel]. Whereas
/// [EventChannel] receives a stream of events from platform plugins, this
/// channel sends a stream of events to the handler listening on the
/// framework-side.
///
/// The channel [name] must not be null. If no [codec] is provided, then
/// [StandardMethodCodec] is used. If no [binaryMessenger] is provided, then
/// [pluginBinaryMessenger], which sends messages to the framework-side,
/// is used.
class PluginEventChannel<T> {
/// Creates a new plugin event channel.
const PluginEventChannel(
this.name, [
this.codec = const StandardMethodCodec(),
BinaryMessenger binaryMessenger,
]) : assert(name != null),
assert(codec != null),
_binaryMessenger = binaryMessenger;
/// The logical channel on which communication happens.
///
/// This must not be null.
final String name;
/// The message codec used by this channel.
///
/// This must not be null. This defaults to [StandardMethodCodec].
final MethodCodec codec;
/// The messenger used by this channel to send platform messages.
///
/// This must not be null. If not provided, defaults to
/// [pluginBinaryMessenger], which sends messages from the platform-side
/// to the framework-side.
BinaryMessenger get binaryMessenger =>
_binaryMessenger ?? pluginBinaryMessenger;
final BinaryMessenger _binaryMessenger;
/// Set the stream controller for this event channel.
set controller(StreamController<T> controller) {
final _EventChannelHandler<T> handler = _EventChannelHandler<T>(
name,
codec,
controller,
binaryMessenger,
);
binaryMessenger.setMessageHandler(
name, controller == null ? null : handler.handle);
}
}
class _EventChannelHandler<T> {
_EventChannelHandler(this.name, this.codec, this.controller, this.messenger);
final String name;
final MethodCodec codec;
final StreamController<T> controller;
final BinaryMessenger messenger;
StreamSubscription<T> subscription;
Future<ByteData> handle(ByteData message) {
final MethodCall call = codec.decodeMethodCall(message);
switch (call.method) {
case 'listen':
return _listen();
case 'cancel':
return _cancel();
}
return null;
}
// TODO(hterkelsen): Support arguments.
Future<ByteData> _listen() async {
if (subscription != null) {
await subscription.cancel();
}
subscription = controller.stream.listen((dynamic event) {
messenger.send(name, codec.encodeSuccessEnvelope(event));
}, onError: (dynamic error) {
messenger.send(name,
codec.encodeErrorEnvelope(code: 'error', message: error.toString()));
});
return codec.encodeSuccessEnvelope(null);
}
// TODO(hterkelsen): Support arguments.
Future<ByteData> _cancel() async {
if (subscription == null) {
return codec.encodeErrorEnvelope(
code: 'error', message: 'No active stream to cancel.');
}
await subscription.cancel();
subscription = null;
return codec.encodeSuccessEnvelope(null);
}
}