_callback_io.dart 3.58 KB
Newer Older
1 2 3 4
// 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.

5
import 'dart:io' show Platform;
6 7 8 9 10
import 'dart:ui';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

11
import 'common.dart';
12
import 'src/channel.dart';
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

/// The dart:io implementation of [CallbackManager].
///
/// See also:
///
///  * `_callback_web.dart`, which has the dart:html implementation
CallbackManager get callbackManager => _singletonCallbackManager;

/// IOCallbackManager singleton.
final IOCallbackManager _singletonCallbackManager = IOCallbackManager();

/// Manages communication between `integration_tests` and the `driver_tests`.
///
/// This is the dart:io implementation.
class IOCallbackManager implements CallbackManager {
  @override
  Future<Map<String, dynamic>> callback(
      Map<String, String> params, IntegrationTestResults testRunner) async {
31
    final String command = params['command']!;
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
    Map<String, String> response;
    switch (command) {
      case 'request_data':
        final bool allTestsPassed = await testRunner.allTestsPassed.future;
        response = <String, String>{
          'message': allTestsPassed
              ? Response.allTestsPassed(data: testRunner.reportData).toJson()
              : Response.someTestsFailed(
                  testRunner.failureMethodsDetails,
                  data: testRunner.reportData,
                ).toJson(),
        };
        break;
      case 'get_health':
        response = <String, String>{'status': 'ok'};
        break;
      default:
        throw UnimplementedError('$command is not implemented');
    }
    return <String, dynamic>{
      'isError': false,
      'response': response,
    };
  }

  @override
  void cleanup() {
    // no-op.
    // Add any IO platform specific Completer/Future cleanups to here if any
    // comes up in the future. For example: `WebCallbackManager.cleanup`.
  }

64 65
  // [convertFlutterSurfaceToImage] has been called and [takeScreenshot] is ready to capture the surface (Android only).
  bool _isSurfaceRendered = false;
66 67 68

  @override
  Future<void> convertFlutterSurfaceToImage() async {
69 70 71 72 73
    if (!Platform.isAndroid) {
      // No-op on other platforms.
      return;
    }
    assert(!_isSurfaceRendered, 'Surface already converted to an image');
74 75 76
    await integrationTestChannel.invokeMethod<void>(
      'convertFlutterSurfaceToImage',
    );
77
    _isSurfaceRendered = true;
78 79

    addTearDown(() async {
80
      assert(_isSurfaceRendered, 'Surface is not an image');
81 82 83
      await integrationTestChannel.invokeMethod<void>(
        'revertFlutterImage',
      );
84
      _isSurfaceRendered = false;
85 86 87
    });
  }

88
  @override
89
  Future<Map<String, dynamic>> takeScreenshot(String screenshot) async {
90
    if (Platform.isAndroid && !_isSurfaceRendered) {
91 92 93 94 95
      throw StateError('Call convertFlutterSurfaceToImage() before taking a screenshot');
    }
    integrationTestChannel.setMethodCallHandler(_onMethodChannelCall);
    final List<int>? rawBytes = await integrationTestChannel.invokeMethod<List<int>>(
      'captureScreenshot',
96
      <String, dynamic>{'name': screenshot},
97 98 99 100 101 102 103 104 105 106 107 108 109
    );
    if (rawBytes == null) {
      throw StateError('Expected a list of bytes, but instead captureScreenshot returned null');
    }
    return <String, dynamic>{
      'screenshotName': screenshot,
      'bytes': rawBytes,
    };
  }

  Future<dynamic> _onMethodChannelCall(MethodCall call) async {
    switch (call.method) {
      case 'scheduleFrame':
110
        PlatformDispatcher.instance.scheduleFrame();
111 112 113
        break;
    }
    return null;
114 115
  }
}