mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Towards https://github.com/flutter/flutter/issues/161261. Still need to add a HC (Hybrid Composition) variant, but figured I'd do this incrementally to make it easier to review.
115 lines
3.9 KiB
Dart
115 lines
3.9 KiB
Dart
// 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:convert';
|
|
|
|
import 'package:flutter/services.dart' as flt;
|
|
import 'package:flutter_driver/driver_extension.dart';
|
|
import 'package:flutter_driver/flutter_driver.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'src/common.dart';
|
|
|
|
/// An extension that forwards [NativeCommand]s to a registered plugin.
|
|
const CommandExtension nativeDriverCommands = NativeDriverCommandExtension(
|
|
flt.MethodChannel('native_driver'),
|
|
);
|
|
|
|
/// An extension that forwards [NativeCommand]s to a registered plugin.
|
|
///
|
|
/// This extension is used to communicate with a platform plugin, and relays
|
|
/// [NativeCommand]s to the platform plugin, and resolves the result as a
|
|
/// [NativeResult], both thin wrappers around a `Map<String, Object?>` (JSON
|
|
/// compatible object).
|
|
///
|
|
/// A singleton default instance of this class is [nativeDriverCommands].
|
|
final class NativeDriverCommandExtension implements CommandExtension {
|
|
/// Creates a new [NativeDriverCommandExtension] with the given [channel].
|
|
///
|
|
/// Can be used in exceptional cases where a custom [MethodChannel] is needed;
|
|
/// otherwise, use the singleton [nativeDriverCommands].
|
|
const NativeDriverCommandExtension(this._channel);
|
|
final flt.MethodChannel _channel;
|
|
|
|
@override
|
|
Future<Result> call(
|
|
Command command,
|
|
WidgetController prober,
|
|
CreateFinderFactory finderFactory,
|
|
CommandHandlerFactory handlerFactory,
|
|
) async {
|
|
if (command is! NativeCommand) {
|
|
throw ArgumentError.value(command, 'command', 'Expected a NativeCommand');
|
|
}
|
|
if (await _builtInCall(command.method) case final Result result) {
|
|
return result;
|
|
}
|
|
final Object? result = await _channel.invokeMethod<Object>(command.method, command.arguments);
|
|
if (result == null) {
|
|
return const _MethodChannelResult(<String, Object?>{});
|
|
}
|
|
if (result is! Map<Object?, Object?>) {
|
|
throw ArgumentError.value(
|
|
result,
|
|
'result',
|
|
'Expected a Map<String, Object?>, got ${result.runtimeType}',
|
|
);
|
|
}
|
|
return _MethodChannelResult(result.cast());
|
|
}
|
|
|
|
// While these could have been implemented in native code, they are already
|
|
// available as engine-bundled platform plugins, so using them directly
|
|
// reduces the amount of code to be written and maintained.
|
|
Future<Result?> _builtInCall(String method) async {
|
|
switch (method) {
|
|
case 'rotate_landscape':
|
|
await flt.SystemChrome.setPreferredOrientations(const <flt.DeviceOrientation>[
|
|
flt.DeviceOrientation.landscapeLeft,
|
|
]);
|
|
return Result.empty;
|
|
case 'rotate_default':
|
|
await flt.SystemChrome.setPreferredOrientations(const <flt.DeviceOrientation>[]);
|
|
return Result.empty;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@override
|
|
String get commandKind => 'native_driver';
|
|
|
|
@override
|
|
NativeCommand deserialize(
|
|
Map<String, String> params,
|
|
DeserializeFinderFactory finderFactory,
|
|
DeserializeCommandFactory commandFactory,
|
|
) {
|
|
final String? method = params['method'];
|
|
if (method == null) {
|
|
throw ArgumentError.value(params, 'params', 'Missing method');
|
|
}
|
|
final String? arguments = params['arguments'];
|
|
final Map<String, Object?>? decoded;
|
|
if (arguments == null) {
|
|
decoded = null;
|
|
} else {
|
|
final Object? intermediate = json.decode(arguments);
|
|
if (intermediate is! Map<String, Object?>) {
|
|
throw ArgumentError.value(arguments, 'arguments', 'Expected a Map<String, Object?>');
|
|
}
|
|
decoded = intermediate;
|
|
}
|
|
return NativeCommand(method, arguments: decoded);
|
|
}
|
|
}
|
|
|
|
final class _MethodChannelResult implements Result {
|
|
const _MethodChannelResult(this._json);
|
|
final Map<String, Object?> _json;
|
|
|
|
@override
|
|
Map<String, Object?> toJson() => _json;
|
|
}
|