screenshot method

Future<List<int>> screenshot ()

Take a screenshot.

The image will be returned as a PNG.

Implementation

Future<List<int>> screenshot() async {
  // HACK: this artificial delay here is to deal with a race between the
  //       driver script and the GPU thread. The issue is that driver API
  //       synchronizes with the framework based on transient callbacks, which
  //       are out of sync with the GPU thread. Here's the timeline of events
  //       in ASCII art:
  //
  //       -------------------------------------------------------------------
  //       Without this delay:
  //       -------------------------------------------------------------------
  //       UI    : <-- build -->
  //       GPU   :               <-- rasterize -->
  //       Gap   :              | random |
  //       Driver:                        <-- screenshot -->
  //
  //       In the diagram above, the gap is the time between the last driver
  //       action taken, such as a `tap()`, and the subsequent call to
  //       `screenshot()`. The gap is random because it is determined by the
  //       unpredictable network communication between the driver process and
  //       the application. If this gap is too short, which it typically will
  //       be, the screenshot is taken before the GPU thread is done
  //       rasterizing the frame, so the screenshot of the previous frame is
  //       taken, which is wrong.
  //
  //       -------------------------------------------------------------------
  //       With this delay, if we're lucky:
  //       -------------------------------------------------------------------
  //       UI    : <-- build -->
  //       GPU   :               <-- rasterize -->
  //       Gap   :              |    2 seconds or more   |
  //       Driver:                                        <-- screenshot -->
  //
  //       The two-second gap should be long enough for the GPU thread to
  //       finish rasterizing the frame, but not longer than necessary to keep
  //       driver tests as fast a possible.
  //
  //       -------------------------------------------------------------------
  //       With this delay, if we're not lucky:
  //       -------------------------------------------------------------------
  //       UI    : <-- build -->
  //       GPU   :               <-- rasterize randomly slow today -->
  //       Gap   :              |    2 seconds or more   |
  //       Driver:                                        <-- screenshot -->
  //
  //       In practice, sometimes the device gets really busy for a while and
  //       even two seconds isn't enough, which means that this is still racy
  //       and a source of flakes.
  await Future<void>.delayed(const Duration(seconds: 2));

  final Map<String, dynamic> result = await _peer.sendRequest('_flutter.screenshot');
  return base64.decode(result['screenshot']);
}