291 lines
11 KiB
Dart
291 lines
11 KiB
Dart
// Copyright 2019 The Chromium 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 'message.dart';
|
|
|
|
/// A Flutter Driver command that waits until a given [condition] is satisfied.
|
|
class WaitForCondition extends Command {
|
|
/// Creates a command that waits for the given [condition] is met.
|
|
///
|
|
/// The [condition] argument must not be null.
|
|
const WaitForCondition(this.condition, {Duration timeout})
|
|
: assert(condition != null),
|
|
super(timeout: timeout);
|
|
|
|
/// Deserializes this command from the value generated by [serialize].
|
|
///
|
|
/// The [json] argument cannot be null.
|
|
WaitForCondition.deserialize(Map<String, String> json)
|
|
: assert(json != null),
|
|
condition = _deserialize(json),
|
|
super.deserialize(json);
|
|
|
|
/// The condition that this command shall wait for.
|
|
final SerializableWaitCondition condition;
|
|
|
|
@override
|
|
Map<String, String> serialize() => super.serialize()..addAll(condition.serialize());
|
|
|
|
@override
|
|
String get kind => 'waitForCondition';
|
|
}
|
|
|
|
/// A Flutter Driver command that waits until there are no more transient callbacks in the queue.
|
|
///
|
|
/// This command has been deprecated in favor of [WaitForCondition]. Construct
|
|
/// a command that waits until no transient callbacks as follows:
|
|
///
|
|
/// ```dart
|
|
/// WaitForCondition noTransientCallbacks = WaitForCondition(NoTransientCallbacks());
|
|
/// ```
|
|
@Deprecated('This command has been deprecated in favor of WaitForCondition. '
|
|
'Use WaitForCondition command with NoTransientCallbacks.')
|
|
class WaitUntilNoTransientCallbacks extends Command {
|
|
/// Creates a command that waits for there to be no transient callbacks.
|
|
const WaitUntilNoTransientCallbacks({ Duration timeout }) : super(timeout: timeout);
|
|
|
|
/// Deserializes this command from the value generated by [serialize].
|
|
WaitUntilNoTransientCallbacks.deserialize(Map<String, String> json)
|
|
: super.deserialize(json);
|
|
|
|
@override
|
|
String get kind => 'waitUntilNoTransientCallbacks';
|
|
}
|
|
|
|
/// A Flutter Driver command that waits until the frame is synced.
|
|
///
|
|
/// This command has been deprecated in favor of [WaitForCondition]. Construct
|
|
/// a command that waits until no pending frame as follows:
|
|
///
|
|
/// ```dart
|
|
/// WaitForCondition noPendingFrame = WaitForCondition(NoPendingFrame());
|
|
/// ```
|
|
@Deprecated('This command has been deprecated in favor of WaitForCondition. '
|
|
'Use WaitForCondition command with NoPendingFrame.')
|
|
class WaitUntilNoPendingFrame extends Command {
|
|
/// Creates a command that waits until there's no pending frame scheduled.
|
|
const WaitUntilNoPendingFrame({ Duration timeout }) : super(timeout: timeout);
|
|
|
|
/// Deserializes this command from the value generated by [serialize].
|
|
WaitUntilNoPendingFrame.deserialize(Map<String, String> json)
|
|
: super.deserialize(json);
|
|
|
|
@override
|
|
String get kind => 'waitUntilNoPendingFrame';
|
|
}
|
|
|
|
/// A Flutter Driver command that waits until the Flutter engine rasterizes the
|
|
/// first frame.
|
|
///
|
|
/// {@template flutter.frame_rasterized_vs_presented}
|
|
/// Usually, the time that a frame is rasterized is very close to the time that
|
|
/// it gets presented on the display. Specifically, rasterization is the last
|
|
/// expensive phase of a frame that's still in Flutter's control.
|
|
/// {@endtemplate}
|
|
///
|
|
/// This command has been deprecated in favor of [WaitForCondition]. Construct
|
|
/// a command that waits until no pending frame as follows:
|
|
///
|
|
/// ```dart
|
|
/// WaitForCondition firstFrameRasterized = WaitForCondition(FirstFrameRasterized());
|
|
/// ```
|
|
@Deprecated('This command has been deprecated in favor of WaitForCondition. '
|
|
'Use WaitForCondition command with FirstFrameRasterized.')
|
|
class WaitUntilFirstFrameRasterized extends Command {
|
|
/// Creates this command.
|
|
const WaitUntilFirstFrameRasterized({ Duration timeout }) : super(timeout: timeout);
|
|
|
|
/// Deserializes this command from the value generated by [serialize].
|
|
WaitUntilFirstFrameRasterized.deserialize(Map<String, String> json)
|
|
: super.deserialize(json);
|
|
|
|
@override
|
|
String get kind => 'waitUntilFirstFrameRasterized';
|
|
}
|
|
|
|
/// Thrown to indicate a serialization error.
|
|
class SerializationException implements Exception {
|
|
/// Creates a [SerializationException] with an optional error message.
|
|
const SerializationException([this.message]);
|
|
|
|
/// The error message, possibly null.
|
|
final String message;
|
|
|
|
@override
|
|
String toString() => 'SerializationException($message)';
|
|
}
|
|
|
|
/// Base class for Flutter Driver wait conditions, objects that describe conditions
|
|
/// the driver can wait for.
|
|
///
|
|
/// This class is sent from the driver script running on the host to the driver
|
|
/// extension on device to perform waiting on a given condition. In the extension,
|
|
/// it will be converted to a [WaitCondition] that actually defines the wait logic.
|
|
///
|
|
/// If you subclass this, you also need to implement a [WaitCondition] in the extension.
|
|
abstract class SerializableWaitCondition {
|
|
/// A const constructor to allow subclasses to be const.
|
|
const SerializableWaitCondition();
|
|
|
|
/// Identifies the name of the wait condition.
|
|
String get conditionName;
|
|
|
|
/// Serializes the object to JSON.
|
|
Map<String, String> serialize() {
|
|
return <String, String>{
|
|
'conditionName': conditionName
|
|
};
|
|
}
|
|
}
|
|
|
|
/// A condition that waits until no transient callbacks are scheduled.
|
|
class NoTransientCallbacks extends SerializableWaitCondition {
|
|
/// Creates a [NoTransientCallbacks] condition.
|
|
const NoTransientCallbacks();
|
|
|
|
/// Factory constructor to parse a [NoTransientCallbacks] instance from the
|
|
/// given JSON map.
|
|
///
|
|
/// The [json] argument must not be null.
|
|
factory NoTransientCallbacks.deserialize(Map<String, dynamic> json) {
|
|
assert(json != null);
|
|
if (json['conditionName'] != 'NoTransientCallbacksCondition')
|
|
throw SerializationException('Error occurred during deserializing the NoTransientCallbacksCondition JSON string: $json');
|
|
return const NoTransientCallbacks();
|
|
}
|
|
|
|
@override
|
|
String get conditionName => 'NoTransientCallbacksCondition';
|
|
}
|
|
|
|
/// A condition that waits until no pending frame is scheduled.
|
|
class NoPendingFrame extends SerializableWaitCondition {
|
|
/// Creates a [NoPendingFrame] condition.
|
|
const NoPendingFrame();
|
|
|
|
/// Factory constructor to parse a [NoPendingFrame] instance from the given
|
|
/// JSON map.
|
|
///
|
|
/// The [json] argument must not be null.
|
|
factory NoPendingFrame.deserialize(Map<String, dynamic> json) {
|
|
assert(json != null);
|
|
if (json['conditionName'] != 'NoPendingFrameCondition')
|
|
throw SerializationException('Error occurred during deserializing the NoPendingFrameCondition JSON string: $json');
|
|
return const NoPendingFrame();
|
|
}
|
|
|
|
@override
|
|
String get conditionName => 'NoPendingFrameCondition';
|
|
}
|
|
|
|
/// A condition that waits until the Flutter engine has rasterized the first frame.
|
|
class FirstFrameRasterized extends SerializableWaitCondition {
|
|
/// Creates a [FirstFrameRasterized] condition.
|
|
const FirstFrameRasterized();
|
|
|
|
/// Factory constructor to parse a [FirstFrameRasterized] instance from the
|
|
/// given JSON map.
|
|
///
|
|
/// The [json] argument must not be null.
|
|
factory FirstFrameRasterized.deserialize(Map<String, dynamic> json) {
|
|
assert(json != null);
|
|
if (json['conditionName'] != 'FirstFrameRasterizedCondition')
|
|
throw SerializationException('Error occurred during deserializing the FirstFrameRasterizedCondition JSON string: $json');
|
|
return const FirstFrameRasterized();
|
|
}
|
|
|
|
@override
|
|
String get conditionName => 'FirstFrameRasterizedCondition';
|
|
}
|
|
|
|
/// A condition that waits until there are no pending platform messages.
|
|
class NoPendingPlatformMessages extends SerializableWaitCondition {
|
|
/// Creates a [NoPendingPlatformMessages] condition.
|
|
const NoPendingPlatformMessages();
|
|
|
|
/// Factory constructor to parse a [NoPendingPlatformMessages] instance from the
|
|
/// given JSON map.
|
|
///
|
|
/// The [json] argument must not be null.
|
|
factory NoPendingPlatformMessages.deserialize(Map<String, dynamic> json) {
|
|
assert(json != null);
|
|
if (json['conditionName'] != 'NoPendingPlatformMessagesCondition')
|
|
throw SerializationException('Error occurred during deserializing the NoPendingPlatformMessagesCondition JSON string: $json');
|
|
return const NoPendingPlatformMessages();
|
|
}
|
|
|
|
@override
|
|
String get conditionName => 'NoPendingPlatformMessagesCondition';
|
|
}
|
|
|
|
/// A combined condition that waits until all the given [conditions] are met.
|
|
class CombinedCondition extends SerializableWaitCondition {
|
|
/// Creates a [CombinedCondition] condition.
|
|
///
|
|
/// The [conditions] argument must not be null.
|
|
const CombinedCondition(this.conditions)
|
|
: assert(conditions != null);
|
|
|
|
/// Factory constructor to parse a [CombinedCondition] instance from the
|
|
/// given JSON map.
|
|
///
|
|
/// The [jsonMap] argument must not be null.
|
|
factory CombinedCondition.deserialize(Map<String, dynamic> jsonMap) {
|
|
assert(jsonMap != null);
|
|
if (jsonMap['conditionName'] != 'CombinedCondition')
|
|
throw SerializationException('Error occurred during deserializing the CombinedCondition JSON string: $jsonMap');
|
|
if (jsonMap['conditions'] == null) {
|
|
return const CombinedCondition(<SerializableWaitCondition>[]);
|
|
}
|
|
|
|
final List<SerializableWaitCondition> conditions = <SerializableWaitCondition>[];
|
|
for (Map<String, dynamic> condition in json.decode(jsonMap['conditions'])) {
|
|
conditions.add(_deserialize(condition));
|
|
}
|
|
return CombinedCondition(conditions);
|
|
}
|
|
|
|
/// A list of conditions it waits for.
|
|
final List<SerializableWaitCondition> conditions;
|
|
|
|
@override
|
|
String get conditionName => 'CombinedCondition';
|
|
|
|
@override
|
|
Map<String, String> serialize() {
|
|
final Map<String, String> jsonMap = super.serialize();
|
|
final List<Map<String, String>> jsonConditions = conditions.map(
|
|
(SerializableWaitCondition condition) {
|
|
assert(condition != null);
|
|
return condition.serialize();
|
|
}).toList();
|
|
jsonMap['conditions'] = json.encode(jsonConditions);
|
|
return jsonMap;
|
|
}
|
|
}
|
|
|
|
/// Parses a [SerializableWaitCondition] or its subclass from the given [json] map.
|
|
///
|
|
/// The [json] argument must not be null.
|
|
SerializableWaitCondition _deserialize(Map<String, dynamic> json) {
|
|
assert(json != null);
|
|
final String conditionName = json['conditionName'];
|
|
switch (conditionName) {
|
|
case 'NoTransientCallbacksCondition':
|
|
return NoTransientCallbacks.deserialize(json);
|
|
case 'NoPendingFrameCondition':
|
|
return NoPendingFrame.deserialize(json);
|
|
case 'FirstFrameRasterizedCondition':
|
|
return FirstFrameRasterized.deserialize(json);
|
|
case 'NoPendingPlatformMessagesCondition':
|
|
return NoPendingPlatformMessages.deserialize(json);
|
|
case 'CombinedCondition':
|
|
return CombinedCondition.deserialize(json);
|
|
}
|
|
throw SerializationException(
|
|
'Unsupported wait condition $conditionName in the JSON string $json');
|
|
}
|