main.dart 4.7 KB
Newer Older
1 2 3 4 5
// 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';
6
import 'dart:typed_data';
7 8 9 10
import 'dart:ui' as ui;

import 'package:flutter_driver/driver_extension.dart';

11 12
import 'windows.dart';

13
void drawHelloWorld(ui.FlutterView view) {
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
  final ui.ParagraphStyle style = ui.ParagraphStyle();
  final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(style)
    ..addText('Hello world');
  final ui.Paragraph paragraph = paragraphBuilder.build();

  paragraph.layout(const ui.ParagraphConstraints(width: 100.0));

  final ui.PictureRecorder recorder = ui.PictureRecorder();
  final ui.Canvas canvas = ui.Canvas(recorder);

  canvas.drawParagraph(paragraph, ui.Offset.zero);

  final ui.Picture picture = recorder.endRecording();
  final ui.SceneBuilder sceneBuilder = ui.SceneBuilder()
    ..addPicture(ui.Offset.zero, picture)
    ..pop();

31
  view.render(sceneBuilder.build());
32 33
}

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
Future<void> _waitUntilWindowVisible() async {
  while (!await isWindowVisible()) {
    await Future<void>.delayed(const Duration(milliseconds: 100));
  }
}

void _expectVisible(bool current, bool expect, Completer<String> completer, int frameCount) {
  if (current != expect) {
    try {
      throw 'Window should be ${expect ? 'visible' : 'hidden'} on frame $frameCount';
    } catch (e) {
      if (!completer.isCompleted) {
        completer.completeError(e);
      }
      rethrow;
    }
  }
}

53
void main() async {
54 55 56 57
  // TODO(goderbauer): Create a window if embedder doesn't provide an implicit view to draw into.
  assert(ui.PlatformDispatcher.instance.implicitView != null);
  final ui.FlutterView view = ui.PlatformDispatcher.instance.implicitView!;

58 59 60 61 62 63 64 65 66 67 68 69 70
  // Create a completer to send the window visibility result back to the
  // integration test.
  final Completer<String> visibilityCompleter = Completer<String>();
  enableFlutterDriverExtension(handler: (String? message) async {
    if (message == 'verifyWindowVisibility') {
      return visibilityCompleter.future;
    } else if (message == 'verifyTheme') {
      final bool app = await isAppDarkModeEnabled();
      final bool system = await isSystemDarkModeEnabled();

      return (app == system)
        ? 'success'
        : 'error: app dark mode ($app) does not match system dark mode ($system)';
71 72 73 74 75
    } else if (message == 'verifyStringConversion') {
      // Use a test string that contains code points that fit in both 8 and 16 bits.
      // The code points are passed a list of integers through the method channel,
      // which will use the UTF16 to UTF8 utility function to convert them to a
      // std::string, which should equate to the original expected string.
76
      const String expected = 'ABCℵ';
77 78 79 80 81
      final Int32List codePoints = Int32List.fromList(expected.codeUnits);
      final String converted = await testStringConversion(codePoints);
      return (converted == expected)
        ? 'success'
        : 'error: conversion of UTF16 string to UTF8 failed, expected "${expected.codeUnits}" but got "${converted.codeUnits}"';
82
    }
83

84 85
    throw 'Unrecognized message: $message';
  });
86

87 88
  try {
    if (await isWindowVisible()) {
89
      throw 'Window should be hidden at startup';
90 91
    }

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    int frameCount = 0;
    ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
      // Our goal is to verify that it's `drawHelloWorld` that makes the window
      // appear, not anything else. This requires checking the visibility right
      // before drawing, but since `isWindowVisible` has to be async, and
      // `FlutterView.render` (in `drawHelloWorld`) forbids async before it,
      // this can not be done during a single onBeginFrame. However, we can
      // verify in separate frames to indirectly prove it, by ensuring that
      // no other mechanism can affect isWindowVisible in the first frame at all.
      frameCount += 1;
      switch (frameCount) {
        // The 1st frame: render nothing, just verify that the window is hidden.
        case 1:
          isWindowVisible().then((bool visible) {
            _expectVisible(visible, false, visibilityCompleter, frameCount);
            ui.PlatformDispatcher.instance.scheduleFrame();
          });
        // The 2nd frame: render, which makes the window appear.
        case 2:
          drawHelloWorld(view);
          _waitUntilWindowVisible().then((_) {
            if (!visibilityCompleter.isCompleted) {
              visibilityCompleter.complete('success');
            }
          });
        // Others, in case requested to render.
        default:
          drawHelloWorld(view);
120 121 122
      }
    };
  } catch (e) {
123
    visibilityCompleter.completeError(e);
124 125
    rethrow;
  }
126
  ui.PlatformDispatcher.instance.scheduleFrame();
127
}