diff --git a/android/app/src/main/java/deckers/thibault/aves/channelhandlers/ImageByteStreamHandler.java b/android/app/src/main/java/deckers/thibault/aves/channelhandlers/ImageByteStreamHandler.java index 88888dadb..96a57df08 100644 --- a/android/app/src/main/java/deckers/thibault/aves/channelhandlers/ImageByteStreamHandler.java +++ b/android/app/src/main/java/deckers/thibault/aves/channelhandlers/ImageByteStreamHandler.java @@ -108,7 +108,9 @@ public class ImageByteStreamHandler implements EventChannel.StreamHandler { } else { try (InputStream is = cr.openInputStream(uri)) { if (is != null) { - streamBytes(is); + // TODO TLAD streaming would allow chunk events, but in practice Flutter blocks every time we send a chunk +// streamBytes(is); + success(getBytes(is)); } else { error("getImage-image-read-null", "failed to get image from uri=" + uri, null); } @@ -131,4 +133,17 @@ public class ImageByteStreamHandler implements EventChannel.StreamHandler { success(sub); } } + + // InputStream.readAllBytes is only available from Java 9+ + private byte[] getBytes(InputStream inputStream) throws IOException { + ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + + int len; + while ((len = inputStream.read(buffer)) != -1) { + byteBuffer.write(buffer, 0, len); + } + return byteBuffer.toByteArray(); + } } diff --git a/android/build.gradle b/android/build.gradle index cd23eff88..989c6404c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,6 +14,11 @@ allprojects { google() jcenter() } +// gradle.projectsEvaluated { +// tasks.withType(JavaCompile) { +// options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" +// } +// } } rootProject.buildDir = '../build' diff --git a/lib/services/image_file_service.dart b/lib/services/image_file_service.dart index 73bbc8838..7e2b093e7 100644 --- a/lib/services/image_file_service.dart +++ b/lib/services/image_file_service.dart @@ -1,5 +1,5 @@ import 'dart:async'; -import 'dart:io'; +import 'dart:convert'; import 'dart:typed_data'; import 'package:aves/model/image_entry.dart'; @@ -40,15 +40,18 @@ class ImageFileService { static Future getImage(String uri, String mimeType) { try { - final completer = Completer(); - final bytesBuilder = BytesBuilder(copy: false); + final completer = Completer.sync(); + final sink = _OutputBuffer(); byteChannel.receiveBroadcastStream({ 'uri': uri, 'mimeType': mimeType, }).listen( - (data) => bytesBuilder.add(data as Uint8List), + (chunk) => sink.add(chunk as Uint8List), onError: completer.completeError, - onDone: () => completer.complete(bytesBuilder.takeBytes()), + onDone: () { + sink.close(); + completer.complete(sink.bytes); + }, cancelOnError: true, ); return completer.future; @@ -193,3 +196,37 @@ class MoveOpEvent extends ImageOpEvent { return 'MoveOpEvent{success=$success, uri=$uri, newFields=$newFields}'; } } + +// copied from `consolidateHttpClientResponseBytes` in flutter/foundation +class _OutputBuffer extends ByteConversionSinkBase { + List> _chunks = >[]; + int _contentLength = 0; + Uint8List _bytes; + + @override + void add(List chunk) { + assert(_bytes == null); + _chunks.add(chunk); + _contentLength += chunk.length; + } + + @override + void close() { + if (_bytes != null) { + // We've already been closed; this is a no-op + return; + } + _bytes = Uint8List(_contentLength); + int offset = 0; + for (final List chunk in _chunks) { + _bytes.setRange(offset, offset + chunk.length, chunk); + offset += chunk.length; + } + _chunks = null; + } + + Uint8List get bytes { + assert(_bytes != null); + return _bytes; + } +} diff --git a/lib/utils/constants.dart b/lib/utils/constants.dart index 4ae63867e..f7ca961ba 100644 --- a/lib/utils/constants.dart +++ b/lib/utils/constants.dart @@ -29,6 +29,12 @@ class Constants { static const svgColorFilter = ColorFilter.mode(svgBackground, BlendMode.dstOver); static const List androidDependencies = [ + Dependency( + name: 'CWAC-Document', + license: 'Apache 2.0', + licenseUrl: 'https://github.com/commonsguy/cwac-document/blob/master/LICENSE', + sourceUrl: 'https://github.com/commonsguy/cwac-document', + ), Dependency( name: 'Glide', license: 'Apache 2.0, BSD 2-Clause',