diff --git a/packages/flutter/lib/src/painting/image_decoder.dart b/packages/flutter/lib/src/painting/image_decoder.dart index 6ad409aa0a..9509031cd0 100644 --- a/packages/flutter/lib/src/painting/image_decoder.dart +++ b/packages/flutter/lib/src/painting/image_decoder.dart @@ -4,15 +4,24 @@ import 'dart:async'; import 'dart:typed_data'; -import 'dart:ui' as ui show Image, decodeImageFromList; +import 'dart:ui' as ui show Codec, FrameInfo, Image; + +import 'binding.dart'; /// Creates an image from a list of bytes. /// /// This function attempts to interpret the given bytes an image. If successful, /// the returned [Future] resolves to the decoded image. Otherwise, the [Future] /// resolves to null. -Future decodeImageFromList(Uint8List list) { - final Completer completer = Completer(); - ui.decodeImageFromList(list, completer.complete); - return completer.future; +/// +/// If the image is animated, this returns the first frame. Consider +/// [instantiateImageCodec] if support for animated images is necessary. +/// +/// This function differs from [ui.decodeImageFromList] in that it defers to +/// [PaintingBinding.instantiateImageCodec], and therefore can be mocked in +/// tests. +Future decodeImageFromList(Uint8List bytes) async { + final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodec(bytes); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + return frameInfo.image; } diff --git a/packages/flutter/test/painting/image_decoder_test.dart b/packages/flutter/test/painting/image_decoder_test.dart index 41d3b462e7..a80726ce14 100644 --- a/packages/flutter/test/painting/image_decoder_test.dart +++ b/packages/flutter/test/painting/image_decoder_test.dart @@ -6,15 +6,19 @@ import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/painting.dart'; -import '../flutter_test_alternative.dart'; +import '../flutter_test_alternative.dart'; +import 'binding_test.dart'; import 'image_data.dart'; void main() { + final PaintingBindingSpy binding = PaintingBindingSpy(); test('Image decoder control test', () async { + expect(binding.instantiateImageCodecCalledCount, 0); final ui.Image image = await decodeImageFromList(Uint8List.fromList(kTransparentImage)); expect(image, isNotNull); expect(image.width, 1); expect(image.height, 1); + expect(binding.instantiateImageCodecCalledCount, 1); }); } diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index f51195e65b..b41b7ed855 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -36,6 +36,7 @@ class TestImageProvider extends ImageProvider { } Future main() async { + AutomatedTestWidgetsFlutterBinding(); TestImageProvider.image = await decodeImageFromList(Uint8List.fromList(kTransparentImage)); testWidgets('DecoratedBox handles loading images', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/shape_decoration_test.dart b/packages/flutter/test/widgets/shape_decoration_test.dart index 79a402b0a8..dc8297614a 100644 --- a/packages/flutter/test/widgets/shape_decoration_test.dart +++ b/packages/flutter/test/widgets/shape_decoration_test.dart @@ -14,6 +14,7 @@ import '../rendering/mock_canvas.dart'; import 'test_border.dart' show TestBorder; Future main() async { + AutomatedTestWidgetsFlutterBinding(); final ui.Image rawImage = await decodeImageFromList(Uint8List.fromList(kTransparentImage)); final ImageProvider image = TestImageProvider(0, 0, image: rawImage); testWidgets('ShapeDecoration.image', (WidgetTester tester) async {