[image_picker_platform_interface] migrate to nnbd  (#3492)

diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md
index 581cf18..fc953e4 100644
--- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md
+++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 2.0.0-nullsafety
+
+* Migrate to null safety.
+* Breaking Changes:
+    * Removed the deprecated methods: `ImagePickerPlatform.retrieveLostDataAsDartIoFile`,`ImagePickerPlatform.pickImagePath` and `ImagePickerPlatform.pickVideoPath`.
+    * Removed deprecated class: `LostDataResponse`.
+
 ## 1.1.6
 
 * Fix test asset file location.
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart
index 71704b6..8535f9d 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart
@@ -3,11 +3,10 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
-import 'package:meta/meta.dart' show required, visibleForTesting;
+import 'package:meta/meta.dart' show visibleForTesting;
 
 import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
 
@@ -20,14 +19,14 @@
   MethodChannel get channel => _channel;
 
   @override
-  Future<PickedFile> pickImage({
-    @required ImageSource source,
-    double maxWidth,
-    double maxHeight,
-    int imageQuality,
+  Future<PickedFile?> pickImage({
+    required ImageSource source,
+    double? maxWidth,
+    double? maxHeight,
+    int? imageQuality,
     CameraDevice preferredCameraDevice = CameraDevice.rear,
   }) async {
-    String path = await pickImagePath(
+    String? path = await _pickImagePath(
       source: source,
       maxWidth: maxWidth,
       maxHeight: maxHeight,
@@ -37,15 +36,13 @@
     return path != null ? PickedFile(path) : null;
   }
 
-  @override
-  Future<String> pickImagePath({
-    @required ImageSource source,
-    double maxWidth,
-    double maxHeight,
-    int imageQuality,
+  Future<String?> _pickImagePath({
+    required ImageSource source,
+    double? maxWidth,
+    double? maxHeight,
+    int? imageQuality,
     CameraDevice preferredCameraDevice = CameraDevice.rear,
   }) {
-    assert(source != null);
     if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
       throw ArgumentError.value(
           imageQuality, 'imageQuality', 'must be between 0 and 100');
@@ -72,12 +69,12 @@
   }
 
   @override
-  Future<PickedFile> pickVideo({
-    @required ImageSource source,
+  Future<PickedFile?> pickVideo({
+    required ImageSource source,
     CameraDevice preferredCameraDevice = CameraDevice.rear,
-    Duration maxDuration,
+    Duration? maxDuration,
   }) async {
-    String path = await pickVideoPath(
+    String? path = await _pickVideoPath(
       source: source,
       maxDuration: maxDuration,
       preferredCameraDevice: preferredCameraDevice,
@@ -85,13 +82,11 @@
     return path != null ? PickedFile(path) : null;
   }
 
-  @override
-  Future<String> pickVideoPath({
-    @required ImageSource source,
+  Future<String?> _pickVideoPath({
+    required ImageSource source,
     CameraDevice preferredCameraDevice = CameraDevice.rear,
-    Duration maxDuration,
+    Duration? maxDuration,
   }) {
-    assert(source != null);
     return _channel.invokeMethod<String>(
       'pickVideo',
       <String, dynamic>{
@@ -104,7 +99,7 @@
 
   @override
   Future<LostData> retrieveLostData() async {
-    final Map<String, dynamic> result =
+    final Map<String, dynamic>? result =
         await _channel.invokeMapMethod<String, dynamic>('retrieve');
 
     if (result == null) {
@@ -113,23 +108,23 @@
 
     assert(result.containsKey('path') ^ result.containsKey('errorCode'));
 
-    final String type = result['type'];
+    final String? type = result['type'];
     assert(type == kTypeImage || type == kTypeVideo);
 
-    RetrieveType retrieveType;
+    RetrieveType? retrieveType;
     if (type == kTypeImage) {
       retrieveType = RetrieveType.image;
     } else if (type == kTypeVideo) {
       retrieveType = RetrieveType.video;
     }
 
-    PlatformException exception;
+    PlatformException? exception;
     if (result.containsKey('errorCode')) {
       exception = PlatformException(
           code: result['errorCode'], message: result['errorMessage']);
     }
 
-    final String path = result['path'];
+    final String? path = result['path'];
 
     return LostData(
       file: path != null ? PickedFile(path) : null,
@@ -137,40 +132,4 @@
       type: retrieveType,
     );
   }
-
-  @override
-  // ignore: deprecated_member_use_from_same_package
-  Future<LostDataResponse> retrieveLostDataAsDartIoFile() async {
-    final Map<String, dynamic> result =
-        await _channel.invokeMapMethod<String, dynamic>('retrieve');
-    if (result == null) {
-      // ignore: deprecated_member_use_from_same_package
-      return LostDataResponse.empty();
-    }
-    assert(result.containsKey('path') ^ result.containsKey('errorCode'));
-
-    final String type = result['type'];
-    assert(type == kTypeImage || type == kTypeVideo);
-
-    RetrieveType retrieveType;
-    if (type == kTypeImage) {
-      retrieveType = RetrieveType.image;
-    } else if (type == kTypeVideo) {
-      retrieveType = RetrieveType.video;
-    }
-
-    PlatformException exception;
-    if (result.containsKey('errorCode')) {
-      exception = PlatformException(
-          code: result['errorCode'], message: result['errorMessage']);
-    }
-
-    final String path = result['path'];
-
-    // ignore: deprecated_member_use_from_same_package
-    return LostDataResponse(
-        file: path == null ? null : File(path),
-        exception: exception,
-        type: retrieveType);
-  }
 }
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart
index cbd6041..44b85f1 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import 'package:meta/meta.dart' show required;
 import 'package:plugin_platform_interface/plugin_platform_interface.dart';
 
 import 'package:image_picker_platform_interface/src/method_channel/method_channel_image_picker.dart';
@@ -39,80 +38,6 @@
     _instance = instance;
   }
 
-  /// Returns a [String] containing a path to the image that was picked.
-  ///
-  /// The `source` argument controls where the image comes from. This can
-  /// be either [ImageSource.camera] or [ImageSource.gallery].
-  ///
-  /// If specified, the image will be at most `maxWidth` wide and
-  /// `maxHeight` tall. Otherwise the image will be returned at it's
-  /// original width and height.
-  ///
-  /// The `imageQuality` argument modifies the quality of the image, ranging from 0-100
-  /// where 100 is the original/max quality. If `imageQuality` is null, the image with
-  /// the original quality will be returned. Compression is only supported for certain
-  /// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked,
-  /// a warning message will be logged.
-  ///
-  /// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
-  /// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
-  /// Defaults to [CameraDevice.rear].
-  ///
-  /// In Android, the MainActivity can be destroyed for various reasons. If that happens, the result will be lost
-  /// in this call. You can then call [retrieveLostDataAsDartIoFile] when your app relaunches to retrieve the lost data.
-  @Deprecated('Use pickImage instead.')
-  Future<String> pickImagePath({
-    @required ImageSource source,
-    double maxWidth,
-    double maxHeight,
-    int imageQuality,
-    CameraDevice preferredCameraDevice = CameraDevice.rear,
-  }) {
-    throw UnimplementedError('legacyPickImage() has not been implemented.');
-  }
-
-  /// Returns a [String] containing a path to the video that was picked.
-  ///
-  /// The [source] argument controls where the video comes from. This can
-  /// be either [ImageSource.camera] or [ImageSource.gallery].
-  ///
-  /// The [maxDuration] argument specifies the maximum duration of the captured video. If no [maxDuration] is specified,
-  /// the maximum duration will be infinite.
-  ///
-  /// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
-  /// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
-  /// Defaults to [CameraDevice.rear].
-  ///
-  /// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost
-  /// in this call. You can then call [retrieveLostDataAsDartIoFile] when your app relaunches to retrieve the lost data.
-  @Deprecated('Use pickVideo instead.')
-  Future<String> pickVideoPath({
-    @required ImageSource source,
-    CameraDevice preferredCameraDevice = CameraDevice.rear,
-    Duration maxDuration,
-  }) {
-    throw UnimplementedError('pickVideoPath() has not been implemented.');
-  }
-
-  /// Retrieve the lost image file when [pickImagePath] or [pickVideoPath] failed because the  MainActivity is destroyed. (Android only)
-  ///
-  /// Image or video can be lost if the MainActivity is destroyed. And there is no guarantee that the MainActivity is always alive.
-  /// Call this method to retrieve the lost data and process the data according to your APP's business logic.
-  ///
-  /// Returns a [LostDataResponse] if successfully retrieved the lost data. The [LostDataResponse] can represent either a
-  /// successful image/video selection, or a failure.
-  ///
-  /// Calling this on a non-Android platform will throw [UnimplementedError] exception.
-  ///
-  /// See also:
-  /// * [LostDataResponse], for what's included in the response.
-  /// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more information on MainActivity destruction.
-  @Deprecated('Use retrieveLostData instead.')
-  Future<LostDataResponse> retrieveLostDataAsDartIoFile() {
-    throw UnimplementedError(
-        'retrieveLostDataAsDartIoFile() has not been implemented.');
-  }
-
   // Next version of the API.
 
   /// Returns a [PickedFile] with the image that was picked.
@@ -141,11 +66,13 @@
   ///
   /// In Android, the MainActivity can be destroyed for various reasons. If that happens, the result will be lost
   /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data.
-  Future<PickedFile> pickImage({
-    @required ImageSource source,
-    double maxWidth,
-    double maxHeight,
-    int imageQuality,
+  ///
+  /// If no images were picked, the return value is null.
+  Future<PickedFile?> pickImage({
+    required ImageSource source,
+    double? maxWidth,
+    double? maxHeight,
+    int? imageQuality,
     CameraDevice preferredCameraDevice = CameraDevice.rear,
   }) {
     throw UnimplementedError('pickImage() has not been implemented.');
@@ -165,10 +92,12 @@
   ///
   /// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost
   /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data.
-  Future<PickedFile> pickVideo({
-    @required ImageSource source,
+  ///
+  /// If no images were picked, the return value is null.
+  Future<PickedFile?> pickVideo({
+    required ImageSource source,
     CameraDevice preferredCameraDevice = CameraDevice.rear,
-    Duration maxDuration,
+    Duration? maxDuration,
   }) {
     throw UnimplementedError('pickVideo() has not been implemented.');
   }
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart
deleted file mode 100644
index d82618b..0000000
--- a/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2017 The Chromium 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:io';
-
-import 'package:flutter/services.dart';
-import 'package:image_picker_platform_interface/src/types/types.dart';
-
-/// The response object of [ImagePicker.retrieveLostData].
-///
-/// Only applies to Android.
-/// See also:
-/// * [ImagePicker.retrieveLostData] for more details on retrieving lost data.
-@Deprecated('Use methods that return a LostData object instead.')
-class LostDataResponse {
-  /// Creates an instance with the given [file], [exception], and [type]. Any of
-  /// the params may be null, but this is never considered to be empty.
-  LostDataResponse({this.file, this.exception, this.type});
-
-  /// Initializes an instance with all member params set to null and considered
-  /// to be empty.
-  LostDataResponse.empty()
-      : file = null,
-        exception = null,
-        type = null,
-        _empty = true;
-
-  /// Whether it is an empty response.
-  ///
-  /// An empty response should have [file], [exception] and [type] to be null.
-  bool get isEmpty => _empty;
-
-  /// The file that was lost in a previous [pickImage] or [pickVideo] call due to MainActivity being destroyed.
-  ///
-  /// Can be null if [exception] exists.
-  final File file;
-
-  /// The exception of the last [pickImage] or [pickVideo].
-  ///
-  /// If the last [pickImage] or [pickVideo] threw some exception before the MainActivity destruction, this variable keeps that
-  /// exception.
-  /// You should handle this exception as if the [pickImage] or [pickVideo] got an exception when the MainActivity was not destroyed.
-  ///
-  /// Note that it is not the exception that caused the destruction of the MainActivity.
-  final PlatformException exception;
-
-  /// Can either be [RetrieveType.image] or [RetrieveType.video];
-  final RetrieveType type;
-
-  bool _empty = false;
-}
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart
index 285294e..2b078ef 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart
@@ -52,7 +52,7 @@
   /// If `end` is present, only up to byte-index `end` will be read. Otherwise, until end of file.
   ///
   /// In order to make sure that system resources are freed, the stream must be read to completion or the subscription on the stream must be cancelled.
-  Stream<Uint8List> openRead([int start, int end]) {
+  Stream<Uint8List> openRead([int? start, int? end]) {
     throw UnimplementedError('openRead() has not been implemented.');
   }
 }
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart
index ee51450..b855eb3 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart
@@ -10,19 +10,19 @@
 /// It wraps the bytes of a selected file.
 class PickedFile extends PickedFileBase {
   final String path;
-  final Uint8List _initBytes;
+  final Uint8List? _initBytes;
 
   /// Construct a PickedFile object from its ObjectUrl.
   ///
   /// Optionally, this can be initialized with `bytes`
   /// so no http requests are performed to retrieve files later.
-  PickedFile(this.path, {Uint8List bytes})
+  PickedFile(this.path, {Uint8List? bytes})
       : _initBytes = bytes,
         super(path);
 
   Future<Uint8List> get _bytes async {
     if (_initBytes != null) {
-      return Future.value(UnmodifiableUint8ListView(_initBytes));
+      return Future.value(UnmodifiableUint8ListView(_initBytes!));
     }
     return http.readBytes(Uri.parse(path));
   }
@@ -38,7 +38,7 @@
   }
 
   @override
-  Stream<Uint8List> openRead([int start, int end]) async* {
+  Stream<Uint8List> openRead([int? start, int? end]) async* {
     final bytes = await _bytes;
     yield bytes.sublist(start ?? 0, end ?? bytes.length);
   }
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart
index dd64558..4b56add 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart
@@ -29,7 +29,7 @@
   }
 
   @override
-  Stream<Uint8List> openRead([int start, int end]) {
+  Stream<Uint8List> openRead([int? start, int? end]) {
     return _file
         .openRead(start ?? 0, end)
         .map((chunk) => Uint8List.fromList(chunk));
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart
index b94e69d..831c7bd 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart
@@ -31,7 +31,7 @@
   /// The file that was lost in a previous [pickImage] or [pickVideo] call due to MainActivity being destroyed.
   ///
   /// Can be null if [exception] exists.
-  final PickedFile file;
+  final PickedFile? file;
 
   /// The exception of the last [pickImage] or [pickVideo].
   ///
@@ -40,10 +40,12 @@
   /// You should handle this exception as if the [pickImage] or [pickVideo] got an exception when the MainActivity was not destroyed.
   ///
   /// Note that it is not the exception that caused the destruction of the MainActivity.
-  final PlatformException exception;
+  final PlatformException? exception;
 
   /// Can either be [RetrieveType.image] or [RetrieveType.video];
-  final RetrieveType type;
+  ///
+  /// If the lost data is empty, this will be null.
+  final RetrieveType? type;
 
   bool _empty = false;
 }
diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart
index 9c44fae..f38a4ec 100644
--- a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart
+++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart
@@ -1,6 +1,5 @@
 export 'camera_device.dart';
 export 'image_source.dart';
-export 'lost_data_response.dart';
 export 'retrieve_type.dart';
 export 'picked_file/picked_file.dart';
 
diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml
index b9ad12a..d5f5ce9 100644
--- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml
+++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml
@@ -3,21 +3,20 @@
 homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.1.6
+version: 2.0.0-nullsafety
 
 dependencies:
   flutter:
     sdk: flutter
-  meta: ^1.1.8
-  http: ^0.12.1
-  plugin_platform_interface: ^1.0.2
+  meta: ^1.3.0-nullsafety.6
+  http: ^0.13.0-nullsafety.0
+  plugin_platform_interface: ^1.1.0-nullsafety.2
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  mockito: ^4.1.1
-  pedantic: ^1.8.0+1
+  pedantic: ^1.10.0-nullsafety.3
 
 environment:
-  sdk: ">=2.5.0 <3.0.0"
+  sdk: ">=2.12.0-0 <3.0.0"
   flutter: ">=1.10.0"
diff --git a/packages/image_picker/image_picker_platform_interface/test/method_channel_image_picker_test.dart b/packages/image_picker/image_picker_platform_interface/test/method_channel_image_picker_test.dart
deleted file mode 100644
index ddaad3d..0000000
--- a/packages/image_picker/image_picker_platform_interface/test/method_channel_image_picker_test.dart
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright 2019 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 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
-import 'package:image_picker_platform_interface/src/method_channel/method_channel_image_picker.dart';
-
-void main() {
-  TestWidgetsFlutterBinding.ensureInitialized();
-
-  group('$MethodChannelImagePicker', () {
-    MethodChannelImagePicker picker = MethodChannelImagePicker();
-
-    final List<MethodCall> log = <MethodCall>[];
-
-    setUp(() {
-      picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
-        log.add(methodCall);
-        return '';
-      });
-
-      log.clear();
-    });
-
-    group('#pickImagePath', () {
-      test('passes the image source argument correctly', () async {
-        await picker.pickImagePath(source: ImageSource.camera);
-        await picker.pickImagePath(source: ImageSource.gallery);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': null,
-              'maxHeight': null,
-              'imageQuality': null,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 1,
-              'maxWidth': null,
-              'maxHeight': null,
-              'imageQuality': null,
-              'cameraDevice': 0
-            }),
-          ],
-        );
-      });
-
-      test('passes the width and height arguments correctly', () async {
-        await picker.pickImagePath(source: ImageSource.camera);
-        await picker.pickImagePath(
-          source: ImageSource.camera,
-          maxWidth: 10.0,
-        );
-        await picker.pickImagePath(
-          source: ImageSource.camera,
-          maxHeight: 10.0,
-        );
-        await picker.pickImagePath(
-          source: ImageSource.camera,
-          maxWidth: 10.0,
-          maxHeight: 20.0,
-        );
-        await picker.pickImagePath(
-            source: ImageSource.camera, maxWidth: 10.0, imageQuality: 70);
-        await picker.pickImagePath(
-            source: ImageSource.camera, maxHeight: 10.0, imageQuality: 70);
-        await picker.pickImagePath(
-            source: ImageSource.camera,
-            maxWidth: 10.0,
-            maxHeight: 20.0,
-            imageQuality: 70);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': null,
-              'maxHeight': null,
-              'imageQuality': null,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': 10.0,
-              'maxHeight': null,
-              'imageQuality': null,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': null,
-              'maxHeight': 10.0,
-              'imageQuality': null,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': 10.0,
-              'maxHeight': 20.0,
-              'imageQuality': null,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': 10.0,
-              'maxHeight': null,
-              'imageQuality': 70,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': null,
-              'maxHeight': 10.0,
-              'imageQuality': 70,
-              'cameraDevice': 0
-            }),
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': 10.0,
-              'maxHeight': 20.0,
-              'imageQuality': 70,
-              'cameraDevice': 0
-            }),
-          ],
-        );
-      });
-
-      test('does not accept a negative width or height argument', () {
-        expect(
-          () =>
-              picker.pickImagePath(source: ImageSource.camera, maxWidth: -1.0),
-          throwsArgumentError,
-        );
-
-        expect(
-          () =>
-              picker.pickImagePath(source: ImageSource.camera, maxHeight: -1.0),
-          throwsArgumentError,
-        );
-      });
-
-      test('handles a null image path response gracefully', () async {
-        picker.channel
-            .setMockMethodCallHandler((MethodCall methodCall) => null);
-
-        expect(await picker.pickImagePath(source: ImageSource.gallery), isNull);
-        expect(await picker.pickImagePath(source: ImageSource.camera), isNull);
-      });
-
-      test('camera position defaults to back', () async {
-        await picker.pickImagePath(source: ImageSource.camera);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': null,
-              'maxHeight': null,
-              'imageQuality': null,
-              'cameraDevice': 0,
-            }),
-          ],
-        );
-      });
-
-      test('camera position can set to front', () async {
-        await picker.pickImagePath(
-            source: ImageSource.camera,
-            preferredCameraDevice: CameraDevice.front);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickImage', arguments: <String, dynamic>{
-              'source': 0,
-              'maxWidth': null,
-              'maxHeight': null,
-              'imageQuality': null,
-              'cameraDevice': 1,
-            }),
-          ],
-        );
-      });
-    });
-
-    group('#pickVideoPath', () {
-      test('passes the image source argument correctly', () async {
-        await picker.pickVideoPath(source: ImageSource.camera);
-        await picker.pickVideoPath(source: ImageSource.gallery);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'cameraDevice': 0,
-              'maxDuration': null,
-            }),
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 1,
-              'cameraDevice': 0,
-              'maxDuration': null,
-            }),
-          ],
-        );
-      });
-
-      test('passes the duration argument correctly', () async {
-        await picker.pickVideoPath(source: ImageSource.camera);
-        await picker.pickVideoPath(
-            source: ImageSource.camera,
-            maxDuration: const Duration(seconds: 10));
-        await picker.pickVideoPath(
-            source: ImageSource.camera,
-            maxDuration: const Duration(minutes: 1));
-        await picker.pickVideoPath(
-            source: ImageSource.camera, maxDuration: const Duration(hours: 1));
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'maxDuration': null,
-              'cameraDevice': 0,
-            }),
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'maxDuration': 10,
-              'cameraDevice': 0,
-            }),
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'maxDuration': 60,
-              'cameraDevice': 0,
-            }),
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'maxDuration': 3600,
-              'cameraDevice': 0,
-            }),
-          ],
-        );
-      });
-
-      test('handles a null video path response gracefully', () async {
-        picker.channel
-            .setMockMethodCallHandler((MethodCall methodCall) => null);
-
-        expect(await picker.pickVideoPath(source: ImageSource.gallery), isNull);
-        expect(await picker.pickVideoPath(source: ImageSource.camera), isNull);
-      });
-
-      test('camera position defaults to back', () async {
-        await picker.pickVideoPath(source: ImageSource.camera);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'cameraDevice': 0,
-              'maxDuration': null,
-            }),
-          ],
-        );
-      });
-
-      test('camera position can set to front', () async {
-        await picker.pickVideoPath(
-            source: ImageSource.camera,
-            preferredCameraDevice: CameraDevice.front);
-
-        expect(
-          log,
-          <Matcher>[
-            isMethodCall('pickVideo', arguments: <String, dynamic>{
-              'source': 0,
-              'maxDuration': null,
-              'cameraDevice': 1,
-            }),
-          ],
-        );
-      });
-    });
-
-    group('#retrieveLostDataAsDartIoFile', () {
-      test('retrieveLostData get success response', () async {
-        picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
-          return <String, String>{
-            'type': 'image',
-            'path': '/example/path',
-          };
-        });
-        // ignore: deprecated_member_use_from_same_package
-        final LostDataResponse response =
-            await picker.retrieveLostDataAsDartIoFile();
-        expect(response.type, RetrieveType.image);
-        expect(response.file.path, '/example/path');
-      });
-
-      test('retrieveLostData get error response', () async {
-        picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
-          return <String, String>{
-            'type': 'video',
-            'errorCode': 'test_error_code',
-            'errorMessage': 'test_error_message',
-          };
-        });
-        // ignore: deprecated_member_use_from_same_package
-        final LostDataResponse response =
-            await picker.retrieveLostDataAsDartIoFile();
-        expect(response.type, RetrieveType.video);
-        expect(response.exception.code, 'test_error_code');
-        expect(response.exception.message, 'test_error_message');
-      });
-
-      test('retrieveLostData get null response', () async {
-        picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
-          return null;
-        });
-        expect((await picker.retrieveLostDataAsDartIoFile()).isEmpty, true);
-      });
-
-      test('retrieveLostData get both path and error should throw', () async {
-        picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
-          return <String, String>{
-            'type': 'video',
-            'errorCode': 'test_error_code',
-            'errorMessage': 'test_error_message',
-            'path': '/example/path',
-          };
-        });
-        expect(picker.retrieveLostDataAsDartIoFile(), throwsAssertionError);
-      });
-    }, skip: isBrowser);
-  });
-}
diff --git a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart
index e7abe37..df35f8f 100644
--- a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart
+++ b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart
@@ -312,7 +312,8 @@
         // ignore: deprecated_member_use_from_same_package
         final LostData response = await picker.retrieveLostData();
         expect(response.type, RetrieveType.image);
-        expect(response.file.path, '/example/path');
+        expect(response.file, isNotNull);
+        expect(response.file!.path, '/example/path');
       });
 
       test('retrieveLostData get error response', () async {
@@ -326,8 +327,9 @@
         // ignore: deprecated_member_use_from_same_package
         final LostData response = await picker.retrieveLostData();
         expect(response.type, RetrieveType.video);
-        expect(response.exception.code, 'test_error_code');
-        expect(response.exception.message, 'test_error_message');
+        expect(response.exception, isNotNull);
+        expect(response.exception!.code, 'test_error_code');
+        expect(response.exception!.message, 'test_error_message');
       });
 
       test('retrieveLostData get null response', () async {
diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart
index 49d84ff..ee0edbe 100644
--- a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart
+++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart
@@ -6,13 +6,12 @@
 
 import 'dart:convert';
 import 'dart:html' as html;
-import 'dart:typed_data';
 
 import 'package:flutter_test/flutter_test.dart';
 import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
 
 final String expectedStringContents = 'Hello, world!';
-final Uint8List bytes = utf8.encode(expectedStringContents);
+final List<int> bytes = utf8.encode(expectedStringContents);
 final html.File textFile = html.File([bytes], 'hello.txt');
 final String textFileUrl = html.Url.createObjectUrl(textFile);
 
diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh
index 9d9e385..7807e6a 100755
--- a/script/build_all_plugins_app.sh
+++ b/script/build_all_plugins_app.sh
@@ -30,6 +30,7 @@
   "google_sign_in_platform_interface"
   "google_sign_in_web"
   "image_picker_platform_interface"
+  "image_picker"
   "instrumentation_adapter"
   "local_auth" # flutter_plugin_android_lifecycle conflict
   "path_provider_linux"
diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh
index 3d0676f..b43d11c 100644
--- a/script/nnbd_plugins.sh
+++ b/script/nnbd_plugins.sh
@@ -21,6 +21,7 @@
   "url_launcher"
   "video_player"
   "webview_flutter"
+  "image_picker"
 )
 
 # This list contains the list of plugins that have *not* been