Update flutter_image per recent changes to framework (#15)

* Update analysis options
* Clean up analysis errors
* Update/fix broken API calls

https://github.com/flutter/flutter/issues/31962
diff --git a/packages/flutter_image/.analysis_options b/packages/flutter_image/.analysis_options
deleted file mode 100644
index 754054c..0000000
--- a/packages/flutter_image/.analysis_options
+++ /dev/null
@@ -1,132 +0,0 @@
-# Specify Dart code analysis options.
-#
-# For a list of lints, see: http://dart-lang.github.io/linter/lints/
-# See the configuration guide for more
-# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer
-#
-# This file contains the analysis options used by Flutter editors, such as Atom.
-
-analyzer:
-  language:
-    enableStrictCallChecks: true
-    enableSuperMixins: true
-    enableAssertInitializer: true
-  strong-mode:
-    implicit-dynamic: false
-  errors:
-    # treat missing required parameters as a warning (not a hint)
-    missing_required_param: warning
-    # treat missing returns as a warning (not a hint)
-    missing_return: warning
-    # allow having TODOs in the code
-    todo: ignore
-  exclude:
-    - 'bin/cache/**'
-    # the following two are relative to the stocks example and the flutter package respectively
-    # see https://github.com/dart-lang/sdk/issues/28463
-    - 'lib/i18n/stock_messages_*.dart'
-    - 'lib/src/http/**'
-
-linter:
-  rules:
-    # these rules are documented on and in the same order as
-    # the Dart Lint rules page to make maintenance easier
-    # http://dart-lang.github.io/linter/lints/
-
-    # === error rules ===
-    - avoid_empty_else
-    - avoid_slow_async_io
-    - cancel_subscriptions
-    # - close_sinks # https://github.com/flutter/flutter/issues/5789
-    # - comment_references # blocked on https://github.com/dart-lang/dartdoc/issues/1153
-    - control_flow_in_finally
-    - empty_statements
-    - hash_and_equals
-    # - invariant_booleans # https://github.com/flutter/flutter/issues/5790
-    - iterable_contains_unrelated_type
-    - list_remove_unrelated_type
-    # - literal_only_boolean_expressions # https://github.com/flutter/flutter/issues/5791
-    - no_adjacent_strings_in_list
-    - no_duplicate_case_values
-    - test_types_in_equals
-    - throw_in_finally
-    - unrelated_type_equality_checks
-    - valid_regexps
-
-    # === style rules ===
-    - always_declare_return_types
-    - always_put_control_body_on_new_line
-    - always_require_non_null_named_parameters
-    - always_specify_types
-    - annotate_overrides
-    # - avoid_annotating_with_dynamic # not yet tested
-    - avoid_as
-    # - avoid_catches_without_on_clauses # not yet tested
-    # - avoid_catching_errors # not yet tested
-    # - avoid_classes_with_only_static_members # not yet tested
-    # - avoid_function_literals_in_foreach_calls # not yet tested
-    - avoid_init_to_null
-    - avoid_null_checks_in_equality_operators
-    # - avoid_positional_boolean_parameters # not yet tested
-    - avoid_return_types_on_setters
-    # - avoid_returning_null # not yet tested
-    # - avoid_returning_this # not yet tested
-    # - avoid_setters_without_getters # not yet tested
-    # - avoid_types_on_closure_parameters # not yet tested
-    - await_only_futures
-    - camel_case_types
-    # - cascade_invocations # not yet tested
-    # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
-    - directives_ordering
-    - empty_catches
-    - empty_constructor_bodies
-    - implementation_imports
-    # - join_return_with_assignment # not yet tested
-    - library_names
-    - library_prefixes
-    - non_constant_identifier_names
-    # - omit_local_variable_types # opposite of always_specify_types
-    # - one_member_abstracts # too many false positives
-    # - only_throw_errors # https://github.com/flutter/flutter/issues/5792
-    - overridden_fields
-    - package_api_docs
-    - package_prefixed_library_names
-    # - parameter_assignments # we do this commonly
-    - prefer_adjacent_string_concatenation
-    - prefer_collection_literals
-    # - prefer_conditional_assignment # not yet tested
-    - prefer_const_constructors
-    # - prefer_constructors_over_static_methods # not yet tested
-    - prefer_contains
-    # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
-    # - prefer_final_fields # https://github.com/dart-lang/linter/issues/506
-    - prefer_final_locals
-    # - prefer_foreach # not yet tested
-    # - prefer_function_declarations_over_variables # not yet tested
-    - prefer_initializing_formals
-    # - prefer_interpolation_to_compose_strings # not yet tested
-    - prefer_is_empty
-    - prefer_is_not_empty
-    # - public_member_api_docs # this is the only difference from .analysis_options_repo
-    # - recursive_getters # https://github.com/dart-lang/linter/issues/452
-    - slash_for_doc_comments
-    - sort_constructors_first
-    - sort_unnamed_constructors_first
-    - super_goes_last
-    # - type_annotate_public_apis # subset of always_specify_types
-    - type_init_formals
-    # - unawaited_futures # https://github.com/flutter/flutter/issues/5793
-    - unnecessary_brace_in_string_interps
-    - unnecessary_getters_setters
-    # - unnecessary_lambdas # https://github.com/dart-lang/linter/issues/498
-    - unnecessary_null_aware_assignments
-    - unnecessary_null_in_if_null_operators
-    # - unnecessary_overrides # https://github.com/dart-lang/linter/issues/626 and https://github.com/dart-lang/linter/issues/627
-    - unnecessary_this
-    - use_rethrow_when_possible
-    # - use_setters_to_change_properties # not yet tested
-    # - use_string_buffers # https://github.com/dart-lang/linter/pull/664
-    # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
-
-    # === pub rules ===
-    - package_names
diff --git a/packages/flutter_image/lib/network.dart b/packages/flutter_image/lib/network.dart
index 0949316..abffcdc 100644
--- a/packages/flutter_image/lib/network.dart
+++ b/packages/flutter_image/lib/network.dart
@@ -24,17 +24,18 @@
 /// [defaultFetchStrategy] to obtain instructions for fetching the URL.
 ///
 /// The image will be cached regardless of cache headers from the server.
+@immutable
 class NetworkImageWithRetry extends ImageProvider<NetworkImageWithRetry> {
   /// Creates an object that fetches the image at the given [url].
   ///
   /// The arguments must not be null.
-  const NetworkImageWithRetry(this.url, { this.scale: 1.0, this.fetchStrategy: defaultFetchStrategy })
+  const NetworkImageWithRetry(this.url, { this.scale = 1.0, this.fetchStrategy = defaultFetchStrategy })
       : assert(url != null),
         assert(scale != null),
         assert(fetchStrategy != null);
 
   /// The HTTP client used to download images.
-  static final io.HttpClient _client = new io.HttpClient();
+  static final io.HttpClient _client = io.HttpClient();
 
   /// The URL from which the image will be fetched.
   final String url;
@@ -65,12 +66,12 @@
 
   @override
   Future<NetworkImageWithRetry> obtainKey(ImageConfiguration configuration) {
-    return new SynchronousFuture<NetworkImageWithRetry>(this);
+    return SynchronousFuture<NetworkImageWithRetry>(this);
   }
 
   @override
   ImageStreamCompleter load(NetworkImageWithRetry key) {
-    return new OneFrameImageStreamCompleter(
+    return OneFrameImageStreamCompleter(
         _loadWithRetry(key),
         informationCollector: () sync* {
           yield ErrorDescription('Image provider: $this');
@@ -83,13 +84,13 @@
     assert(() {
       if (instructions == null) {
         if (fetchStrategy == defaultFetchStrategy) {
-          throw new StateError(
+          throw StateError(
             'The default FetchStrategy returned null FetchInstructions. This\n'
             'is likely a bug in $runtimeType. Please file a bug at\n'
             'https://github.com/flutter/flutter/issues.'
           );
         } else {
-          throw new StateError(
+          throw StateError(
             'The custom FetchStrategy used to fetch $url returned null\n'
             'FetchInstructions. FetchInstructions must never be null, but\n'
             'instead instruct to either make another fetch attempt or give up.'
@@ -103,7 +104,7 @@
   Future<ImageInfo> _loadWithRetry(NetworkImageWithRetry key) async {
     assert(key == this);
 
-    final Stopwatch stopwatch = new Stopwatch()..start();
+    final Stopwatch stopwatch = Stopwatch()..start();
     final Uri resolved = Uri.base.resolve(key.url);
     FetchInstructions instructions = await fetchStrategy(resolved, null);
     _debugCheckInstructions(instructions);
@@ -118,7 +119,7 @@
         final io.HttpClientResponse response = await request.close().timeout(instructions.timeout);
 
         if (response == null || response.statusCode != 200) {
-          throw new FetchFailure._(
+          throw FetchFailure._(
             totalDuration: stopwatch.elapsed,
             attemptCount: attemptCount,
             httpStatusCode: response.statusCode,
@@ -126,7 +127,7 @@
         }
 
         final _Uint8ListBuilder builder = await response.fold(
-          new _Uint8ListBuilder(),
+          _Uint8ListBuilder(),
               (_Uint8ListBuilder buffer, List<int> bytes) => buffer..add(bytes),
         ).timeout(instructions.timeout);
 
@@ -139,7 +140,7 @@
         if (image == null)
           return null;
 
-        return new ImageInfo(
+        return ImageInfo(
           image: image,
           scale: key.scale,
         );
@@ -147,7 +148,7 @@
         request?.close();
         lastFailure = error is FetchFailure
             ? error
-            : new FetchFailure._(
+            : FetchFailure._(
                 totalDuration: stopwatch.elapsed,
                 attemptCount: attemptCount,
                 originalException: error,
@@ -162,7 +163,7 @@
 
     assert(lastFailure != null);
 
-    FlutterError.onError(new FlutterErrorDetails(
+    FlutterError.onError(FlutterErrorDetails(
       exception: lastFailure,
       library: 'package:flutter_image',
       context: ErrorDescription('$runtimeType failed to load ${instructions.uri}'),
@@ -191,7 +192,7 @@
 ///
 /// The instructions are executed as soon as possible after the returned
 /// [Future] resolves. If a delay in necessary between retries, use a delayed
-/// [Future], such as [new Future.delayed]. This is useful for implementing
+/// [Future], such as [Future.delayed]. This is useful for implementing
 /// back-off strategies and for recovering from lack of connectivity.
 ///
 /// [uri] is the last requested image URI. A [FetchStrategy] may choose to use
@@ -205,7 +206,7 @@
 /// [NetworkImageWithRetry] to try again.
 ///
 /// See [NetworkImageWithRetry.defaultFetchStrategy] for an example.
-typedef Future<FetchInstructions> FetchStrategy(Uri uri, FetchFailure failure);
+typedef FetchStrategy = Future<FetchInstructions> Function(Uri uri, FetchFailure failure);
 
 /// Instructions [NetworkImageWithRetry] uses to fetch the image.
 @immutable
@@ -295,9 +296,9 @@
   static const int _kInitialSize = 100000;  // 100KB-ish
 
   int _usedLength = 0;
-  Uint8List _buffer = new Uint8List(_kInitialSize);
+  Uint8List _buffer = Uint8List(_kInitialSize);
 
-  Uint8List get data => new Uint8List.view(_buffer.buffer, 0, _usedLength);
+  Uint8List get data => Uint8List.view(_buffer.buffer, 0, _usedLength);
 
   void add(List<int> bytes) {
     _ensureCanAdd(bytes.length);
@@ -314,7 +315,7 @@
     }
 
     if (newLength != _buffer.length) {
-      final Uint8List newBuffer = new Uint8List(newLength);
+      final Uint8List newBuffer = Uint8List(newLength);
       newBuffer.setAll(0, _buffer);
       newBuffer.setRange(0, _usedLength, _buffer);
       _buffer = newBuffer;
@@ -323,7 +324,7 @@
 }
 
 /// Determines whether the given HTTP [statusCode] is transient.
-typedef bool TransientHttpStatusCodePredicate(int statusCode);
+typedef TransientHttpStatusCodePredicate = bool Function(int statusCode);
 
 /// Builds a [FetchStrategy] function that retries up to a certain amount of
 /// times for up to a certain amount of time.
@@ -333,11 +334,28 @@
 /// those HTTP status codes considered transient by a
 /// [transientHttpStatusCodePredicate] function.
 class FetchStrategyBuilder {
+  /// Creates a fetch strategy builder.
+  ///
+  /// All parameters must be non-null.
+  const FetchStrategyBuilder({
+    this.timeout = const Duration(seconds: 30),
+    this.totalFetchTimeout = const Duration(minutes: 1),
+    this.maxAttempts = 5,
+    this.initialPauseBetweenRetries = const Duration(seconds: 1),
+    this.exponentialBackoffMultiplier = 2,
+    this.transientHttpStatusCodePredicate = defaultTransientHttpStatusCodePredicate,
+  }) : assert(timeout != null),
+       assert(totalFetchTimeout != null),
+       assert(maxAttempts != null),
+       assert(initialPauseBetweenRetries != null),
+       assert(exponentialBackoffMultiplier != null),
+       assert(transientHttpStatusCodePredicate != null);
+
   /// A list of HTTP status codes that can generally be retried.
   ///
   /// You may want to use a different list depending on the needs of your
   /// application.
-  static const List<int> defaultTransientHttpStatusCodes = const <int>[
+  static const List<int> defaultTransientHttpStatusCodes = <int>[
     0,   // Network error
     408, // Request timeout
     500, // Internal server error
@@ -346,23 +364,6 @@
     504 // Gateway timeout
   ];
 
-  /// Creates a fetch strategy builder.
-  ///
-  /// All parameters must be non-null.
-  const FetchStrategyBuilder({
-    this.timeout: const Duration(seconds: 30),
-    this.totalFetchTimeout: const Duration(minutes: 1),
-    this.maxAttempts: 5,
-    this.initialPauseBetweenRetries: const Duration(seconds: 1),
-    this.exponentialBackoffMultiplier: 2,
-    this.transientHttpStatusCodePredicate: defaultTransientHttpStatusCodePredicate,
-  }) : assert(timeout != null),
-       assert(totalFetchTimeout != null),
-       assert(maxAttempts != null),
-       assert(initialPauseBetweenRetries != null),
-       assert(exponentialBackoffMultiplier != null),
-       assert(transientHttpStatusCodePredicate != null);
-
   /// Maximum amount of time a single fetch attempt is allowed to take.
   final Duration timeout;
 
@@ -396,7 +397,7 @@
     return (Uri uri, FetchFailure failure) async {
       if (failure == null) {
         // First attempt. Just load.
-        return new FetchInstructions.attempt(
+        return FetchInstructions.attempt(
           uri: uri,
           timeout: timeout,
         );
@@ -409,15 +410,15 @@
       if (!isRetriableFailure ||  // retrying will not help
           failure.totalDuration > totalFetchTimeout ||  // taking too long
           failure.attemptCount > maxAttempts) {  // too many attempts
-        return new FetchInstructions.giveUp(uri: uri);
+        return FetchInstructions.giveUp(uri: uri);
       }
 
       // Exponential back-off.
       final Duration pauseBetweenRetries = initialPauseBetweenRetries * math.pow(exponentialBackoffMultiplier, failure.attemptCount - 1);
-      await new Future<Null>.delayed(pauseBetweenRetries);
+      await Future<void>.delayed(pauseBetweenRetries);
 
       // Retry.
-      return new FetchInstructions.attempt(
+      return FetchInstructions.attempt(
         uri: uri,
         timeout: timeout,
       );
diff --git a/packages/flutter_image/pubspec.yaml b/packages/flutter_image/pubspec.yaml
index eb48176..b7ffcdd 100644
--- a/packages/flutter_image/pubspec.yaml
+++ b/packages/flutter_image/pubspec.yaml
@@ -1,5 +1,5 @@
 name: flutter_image
-version: 2.0.0-dev
+version: 2.0.0
 description: >
   Image utilities for Flutter: providers, effects, etc
 author: Flutter Team <flutter-dev@googlegroups.com>
@@ -10,7 +10,7 @@
     sdk: flutter
 
 dev_dependencies:
-  quiver: '>=0.24.0 <2.0.0'
+  quiver: '>=0.24.0 <3.0.0'
   test: any
   flutter_test:
     sdk: flutter
diff --git a/packages/flutter_image/test/network_test.dart b/packages/flutter_image/test/network_test.dart
index 8a734ef..46147ae 100644
--- a/packages/flutter_image/test/network_test.dart
+++ b/packages/flutter_image/test/network_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:io' show HttpOverrides;
 import 'package:flutter/foundation.dart';
 import 'package:flutter/painting.dart';
 import 'package:flutter_image/network.dart';
@@ -14,6 +15,9 @@
 }
 
 void main() {
+  AutomatedTestWidgetsFlutterBinding();
+  HttpOverrides.global = null;
+
   group('NetworkImageWithRetry', () {
     setUp(() {
       FlutterError.onError = (FlutterErrorDetails error) {
@@ -26,35 +30,37 @@
     });
 
     test('loads image from network', () async {
-      final NetworkImageWithRetry subject = new NetworkImageWithRetry(
+      final NetworkImageWithRetry subject = NetworkImageWithRetry(
         _imageUrl('immediate_success.png'),
       );
 
-      subject.load(subject).addListener(expectAsync2((ImageInfo image, bool synchronousCall) {
-        expect(image.image.height, 1);
-        expect(image.image.width, 1);
-      }));
+      subject.load(subject).addListener(
+        ImageStreamListener(expectAsync2((ImageInfo image, bool synchronousCall) {
+          expect(image.image.height, 1);
+          expect(image.image.width, 1);
+        })),
+      );
     });
 
     test('retries 6 times then gives up', () async {
       final List<FlutterErrorDetails> errorLog = <FlutterErrorDetails>[];
       FlutterError.onError = errorLog.add;
 
-      final FakeAsync fakeAsync = new FakeAsync();
+      final FakeAsync fakeAsync = FakeAsync();
       final dynamic maxAttemptCountReached = expectAsync0(() {});
 
       int attemptCount = 0;
-      Future<Null> onAttempt() async {
+      Future<void> onAttempt() async {
         expect(attemptCount, lessThan(7));
         if (attemptCount == 6) {
           maxAttemptCountReached();
         }
-        await new Future<Null>.delayed(Duration.ZERO);
+        await Future<void>.delayed(Duration.zero);
         fakeAsync.elapse(const Duration(seconds: 60));
         attemptCount++;
       }
 
-      final NetworkImageWithRetry subject = new NetworkImageWithRetry(
+      final NetworkImageWithRetry subject = NetworkImageWithRetry(
         _imageUrl('error.png'),
         fetchStrategy: (Uri uri, FetchFailure failure) {
           Timer.run(onAttempt);
@@ -64,27 +70,29 @@
         },
       );
 
-      subject.load(subject).addListener(expectAsync2((ImageInfo image, bool synchronousCall) {
-        expect(errorLog.single.exception, const isInstanceOf<FetchFailure>());
-        expect(image, null);
-      }));
+      subject.load(subject).addListener(
+        ImageStreamListener(expectAsync2((ImageInfo image, bool synchronousCall) {
+          expect(errorLog.single.exception, isInstanceOf<FetchFailure>());
+          expect(image, null);
+        })),
+      );
     });
 
     test('gives up immediately on non-retriable errors (HTTP 404)', () async {
       final List<FlutterErrorDetails> errorLog = <FlutterErrorDetails>[];
       FlutterError.onError = errorLog.add;
 
-      final FakeAsync fakeAsync = new FakeAsync();
+      final FakeAsync fakeAsync = FakeAsync();
 
       int attemptCount = 0;
-      Future<Null> onAttempt() async {
+      Future<void> onAttempt() async {
         expect(attemptCount, lessThan(2));
-        await new Future<Null>.delayed(Duration.ZERO);
+        await Future<void>.delayed(Duration.zero);
         fakeAsync.elapse(const Duration(seconds: 60));
         attemptCount++;
       }
 
-      final NetworkImageWithRetry subject = new NetworkImageWithRetry(
+      final NetworkImageWithRetry subject = NetworkImageWithRetry(
         _imageUrl('does_not_exist.png'),
         fetchStrategy: (Uri uri, FetchFailure failure) {
           Timer.run(onAttempt);
@@ -94,24 +102,26 @@
         },
       );
 
-      subject.load(subject).addListener(expectAsync2((ImageInfo image, bool synchronousCall) {
-        expect(errorLog.single.exception, const isInstanceOf<FetchFailure>());
-        expect(image, null);
-      }));
+      subject.load(subject).addListener(
+        ImageStreamListener(expectAsync2((ImageInfo image, bool synchronousCall) {
+          expect(errorLog.single.exception, isInstanceOf<FetchFailure>());
+          expect(image, null);
+        })),
+      );
     });
 
     test('succeeds on successful retry', () async {
-      final NetworkImageWithRetry subject = new NetworkImageWithRetry(
+      final NetworkImageWithRetry subject = NetworkImageWithRetry(
         _imageUrl('error.png'),
         fetchStrategy: (Uri uri, FetchFailure failure) async {
           if (failure == null) {
-            return new FetchInstructions.attempt(
+            return FetchInstructions.attempt(
               uri: uri,
               timeout: const Duration(minutes: 1),
             );
           } else {
             expect(failure.attemptCount, lessThan(2));
-            return new FetchInstructions.attempt(
+            return FetchInstructions.attempt(
               uri: Uri.parse(_imageUrl('immediate_success.png')),
               timeout: const Duration(minutes: 1),
             );
@@ -119,10 +129,12 @@
         },
       );
 
-      subject.load(subject).addListener(expectAsync2((ImageInfo image, bool synchronousCall) {
-        expect(image.image.height, 1);
-        expect(image.image.width, 1);
-      }));
+      subject.load(subject).addListener(
+        ImageStreamListener(expectAsync2((ImageInfo image, bool synchronousCall) {
+          expect(image.image.height, 1);
+          expect(image.image.width, 1);
+        })),
+      );
     });
   });
 }
diff --git a/packages/flutter_image/test/network_test_server.dart b/packages/flutter_image/test/network_test_server.dart
index aa5c212..a6c6eaa 100644
--- a/packages/flutter_image/test/network_test_server.dart
+++ b/packages/flutter_image/test/network_test_server.dart
@@ -7,8 +7,8 @@
 
 const int _kTestServerPort = 11111;
 
-Future<Null> main() async {
-  final HttpServer testServer = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, _kTestServerPort);
+Future<void> main() async {
+  final HttpServer testServer = await HttpServer.bind(InternetAddress.loopbackIPv4, _kTestServerPort);
   await for (HttpRequest request in testServer) {
     if (request.uri.path.endsWith('/immediate_success.png')) {
       request.response.add(_kTransparentImage);
@@ -22,7 +22,7 @@
   }
 }
 
-const List<int> _kTransparentImage = const <int>[
+const List<int> _kTransparentImage = <int>[
   0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
   0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
   0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,